Initial WebM release
diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c new file mode 100644 index 0000000..ac110f7 --- /dev/null +++ b/vp8/common/alloccommon.c
@@ -0,0 +1,251 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "blockd.h" +#include "vpx_mem/vpx_mem.h" +#include "onyxc_int.h" +#include "findnearmv.h" +#include "entropymode.h" +#include "systemdependent.h" +#include "vpxerrors.h" + +#ifdef HAVE_CONFIG_H +#include "vpx_config.h" +#endif + +extern void vp8_init_scan_order_mask(); + +void vp8_update_mode_info_border(MODE_INFO *mi, int rows, int cols) +{ + int i; + vpx_memset(mi - cols - 1, 0, sizeof(MODE_INFO) * cols + 1); + + for (i = 0; i < rows; i++) + { + vpx_memset(&mi[i*cols-1], 0, sizeof(MODE_INFO)); + } +} +void vp8_de_alloc_frame_buffers(VP8_COMMON *oci) +{ + vp8_yv12_de_alloc_frame_buffer(&oci->temp_scale_frame); + vp8_yv12_de_alloc_frame_buffer(&oci->new_frame); + vp8_yv12_de_alloc_frame_buffer(&oci->last_frame); + vp8_yv12_de_alloc_frame_buffer(&oci->golden_frame); + vp8_yv12_de_alloc_frame_buffer(&oci->alt_ref_frame); + vp8_yv12_de_alloc_frame_buffer(&oci->post_proc_buffer); + + vpx_free(oci->above_context[Y1CONTEXT]); + vpx_free(oci->above_context[UCONTEXT]); + vpx_free(oci->above_context[VCONTEXT]); + vpx_free(oci->above_context[Y2CONTEXT]); + vpx_free(oci->mip); + + oci->above_context[Y1CONTEXT] = 0; + oci->above_context[UCONTEXT] = 0; + oci->above_context[VCONTEXT] = 0; + oci->above_context[Y2CONTEXT] = 0; + oci->mip = 0; + + // Structure used to minitor GF useage + if (oci->gf_active_flags != 0) + vpx_free(oci->gf_active_flags); + + oci->gf_active_flags = 0; +} + +int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) +{ + vp8_de_alloc_frame_buffers(oci); + + // our internal buffers are always multiples of 16 + if ((width & 0xf) != 0) + width += 16 - (width & 0xf); + + if ((height & 0xf) != 0) + height += 16 - (height & 0xf); + + + if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + + if (vp8_yv12_alloc_frame_buffer(&oci->new_frame, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + if (vp8_yv12_alloc_frame_buffer(&oci->last_frame, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + if (vp8_yv12_alloc_frame_buffer(&oci->golden_frame, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + if (vp8_yv12_alloc_frame_buffer(&oci->alt_ref_frame, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, VP8BORDERINPIXELS) < 0) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->mb_rows = height >> 4; + oci->mb_cols = width >> 4; + oci->MBs = oci->mb_rows * oci->mb_cols; + oci->mode_info_stride = oci->mb_cols + 1; + oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); + + if (!oci->mip) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->mi = oci->mip + oci->mode_info_stride + 1; + + + oci->above_context[Y1CONTEXT] = vpx_calloc(sizeof(ENTROPY_CONTEXT) * oci->mb_cols * 4 , 1); + + if (!oci->above_context[Y1CONTEXT]) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->above_context[UCONTEXT] = vpx_calloc(sizeof(ENTROPY_CONTEXT) * oci->mb_cols * 2 , 1); + + if (!oci->above_context[UCONTEXT]) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->above_context[VCONTEXT] = vpx_calloc(sizeof(ENTROPY_CONTEXT) * oci->mb_cols * 2 , 1); + + if (!oci->above_context[VCONTEXT]) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->above_context[Y2CONTEXT] = vpx_calloc(sizeof(ENTROPY_CONTEXT) * oci->mb_cols , 1); + + if (!oci->above_context[Y2CONTEXT]) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + vp8_update_mode_info_border(oci->mi, oci->mb_rows, oci->mb_cols); + + // Structures used to minitor GF usage + if (oci->gf_active_flags != 0) + vpx_free(oci->gf_active_flags); + + oci->gf_active_flags = (unsigned char *)vpx_calloc(oci->mb_rows * oci->mb_cols, 1); + + if (!oci->gf_active_flags) + { + vp8_de_alloc_frame_buffers(oci); + return ALLOC_FAILURE; + } + + oci->gf_active_count = oci->mb_rows * oci->mb_cols; + + return 0; +} +void vp8_setup_version(VP8_COMMON *cm) +{ + switch (cm->version) + { + case 0: + cm->no_lpf = 0; + cm->simpler_lpf = 0; + cm->use_bilinear_mc_filter = 0; + cm->full_pixel = 0; + break; + case 1: + cm->no_lpf = 0; + cm->simpler_lpf = 1; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 0; + break; + case 2: + cm->no_lpf = 1; + cm->simpler_lpf = 0; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 0; + break; + case 3: + cm->no_lpf = 1; + cm->simpler_lpf = 1; + cm->use_bilinear_mc_filter = 1; + cm->full_pixel = 1; + break; + default: + //4,5,6,7 are reserved for future use + cm->no_lpf = 0; + cm->simpler_lpf = 0; + cm->use_bilinear_mc_filter = 0; + cm->full_pixel = 0; + break; + } +} +void vp8_create_common(VP8_COMMON *oci) +{ + vp8_machine_specific_config(oci); + vp8_default_coef_probs(oci); + vp8_init_mbmode_probs(oci); + vp8_default_bmode_probs(oci->fc.bmode_prob); + + oci->mb_no_coeff_skip = 1; + oci->no_lpf = 0; + oci->simpler_lpf = 0; + oci->use_bilinear_mc_filter = 0; + oci->full_pixel = 0; + oci->multi_token_partition = ONE_PARTITION; + oci->clr_type = REG_YUV; + oci->clamp_type = RECON_CLAMP_REQUIRED; + + // Initialise reference frame sign bias structure to defaults + vpx_memset(oci->ref_frame_sign_bias, 0, sizeof(oci->ref_frame_sign_bias)); + + // Default disable buffer to buffer copying + oci->copy_buffer_to_gf = 0; + oci->copy_buffer_to_arf = 0; +} + +void vp8_remove_common(VP8_COMMON *oci) +{ + vp8_de_alloc_frame_buffers(oci); +} + +void vp8_initialize_common() +{ + vp8_coef_tree_initialize(); + + vp8_entropy_mode_init(); + + vp8_init_scan_order_mask(); + +}
diff --git a/vp8/common/alloccommon.h b/vp8/common/alloccommon.h new file mode 100644 index 0000000..73c7383 --- /dev/null +++ b/vp8/common/alloccommon.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ALLOCCOMMON_H +#define __INC_ALLOCCOMMON_H + +#include "onyxc_int.h" + +void vp8_create_common(VP8_COMMON *oci); +void vp8_remove_common(VP8_COMMON *oci); +void vp8_de_alloc_frame_buffers(VP8_COMMON *oci); +int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height); +void vp8_setup_version(VP8_COMMON *oci); + +#endif
diff --git a/vp8/common/arm/armv6/bilinearfilter_v6.asm b/vp8/common/arm/armv6/bilinearfilter_v6.asm new file mode 100644 index 0000000..4428cf8 --- /dev/null +++ b/vp8/common/arm/armv6/bilinearfilter_v6.asm
@@ -0,0 +1,237 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_filter_block2d_bil_first_pass_armv6| + EXPORT |vp8_filter_block2d_bil_second_pass_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + +;------------------------------------- +; r0 unsigned char *src_ptr, +; r1 unsigned short *output_ptr, +; r2 unsigned int src_pixels_per_line, +; r3 unsigned int output_height, +; stack unsigned int output_width, +; stack const short *vp8_filter +;------------------------------------- +; The output is transposed stroed in output array to make it easy for second pass filtering. +|vp8_filter_block2d_bil_first_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r4, [sp, #36] ; output width + + mov r12, r3 ; outer-loop counter + sub r2, r2, r4 ; src increment for height loop + + ;;IF ARCHITECTURE=6 + pld [r0] + ;;ENDIF + + ldr r5, [r11] ; load up filter coefficients + + mov r3, r3, lsl #1 ; output_height*2 + add r3, r3, #2 ; plus 2 to make output buffer 4-bit aligned since height is actually (height+1) + + mov r11, r1 ; save output_ptr for each row + + cmp r5, #128 ; if filter coef = 128, then skip the filter + beq bil_null_1st_filter + +|bil_height_loop_1st_v6| + ldrb r6, [r0] ; load source data + ldrb r7, [r0, #1] + ldrb r8, [r0, #2] + mov lr, r4, lsr #2 ; 4-in-parellel loop counter + +|bil_width_loop_1st_v6| + ldrb r9, [r0, #3] + ldrb r10, [r0, #4] + + pkhbt r6, r6, r7, lsl #16 ; src[1] | src[0] + pkhbt r7, r7, r8, lsl #16 ; src[2] | src[1] + + smuad r6, r6, r5 ; apply the filter + pkhbt r8, r8, r9, lsl #16 ; src[3] | src[2] + smuad r7, r7, r5 + pkhbt r9, r9, r10, lsl #16 ; src[4] | src[3] + + smuad r8, r8, r5 + smuad r9, r9, r5 + + add r0, r0, #4 + subs lr, lr, #1 + + add r6, r6, #0x40 ; round_shift_and_clamp + add r7, r7, #0x40 + usat r6, #16, r6, asr #7 + usat r7, #16, r7, asr #7 + + strh r6, [r1], r3 ; result is transposed and stored + + add r8, r8, #0x40 ; round_shift_and_clamp + strh r7, [r1], r3 + add r9, r9, #0x40 + usat r8, #16, r8, asr #7 + usat r9, #16, r9, asr #7 + + strh r8, [r1], r3 ; result is transposed and stored + + ldrneb r6, [r0] ; load source data + strh r9, [r1], r3 + + ldrneb r7, [r0, #1] + ldrneb r8, [r0, #2] + + bne bil_width_loop_1st_v6 + + add r0, r0, r2 ; move to next input row + subs r12, r12, #1 + + ;;IF ARCHITECTURE=6 + pld [r0] + ;;ENDIF + + add r11, r11, #2 ; move over to next column + mov r1, r11 + + bne bil_height_loop_1st_v6 + + ldmia sp!, {r4 - r11, pc} + +|bil_null_1st_filter| +|bil_height_loop_null_1st| + mov lr, r4, lsr #2 ; loop counter + +|bil_width_loop_null_1st| + ldrb r6, [r0] ; load data + ldrb r7, [r0, #1] + ldrb r8, [r0, #2] + ldrb r9, [r0, #3] + + strh r6, [r1], r3 ; store it to immediate buffer + add r0, r0, #4 + strh r7, [r1], r3 + subs lr, lr, #1 + strh r8, [r1], r3 + strh r9, [r1], r3 + + bne bil_width_loop_null_1st + + subs r12, r12, #1 + add r0, r0, r2 ; move to next input line + add r11, r11, #2 ; move over to next column + mov r1, r11 + + bne bil_height_loop_null_1st + + ldmia sp!, {r4 - r11, pc} + + ENDP ; |vp8_filter_block2d_bil_first_pass_armv6| + + +;--------------------------------- +; r0 unsigned short *src_ptr, +; r1 unsigned char *output_ptr, +; r2 int output_pitch, +; r3 unsigned int output_height, +; stack unsigned int output_width, +; stack const short *vp8_filter +;--------------------------------- +|vp8_filter_block2d_bil_second_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r4, [sp, #36] ; output width + + ldr r5, [r11] ; load up filter coefficients + mov r12, r4 ; outer-loop counter = width, since we work on transposed data matrix + mov r11, r1 + + cmp r5, #128 ; if filter coef = 128, then skip the filter + beq bil_null_2nd_filter + +|bil_height_loop_2nd| + ldr r6, [r0] ; load the data + ldr r8, [r0, #4] + ldrh r10, [r0, #8] + mov lr, r3, lsr #2 ; loop counter + +|bil_width_loop_2nd| + pkhtb r7, r6, r8 ; src[1] | src[2] + pkhtb r9, r8, r10 ; src[3] | src[4] + + smuad r6, r6, r5 ; apply filter + smuad r8, r8, r5 ; apply filter + + subs lr, lr, #1 + + smuadx r7, r7, r5 ; apply filter + smuadx r9, r9, r5 ; apply filter + + add r0, r0, #8 + + add r6, r6, #0x40 ; round_shift_and_clamp + add r7, r7, #0x40 + usat r6, #8, r6, asr #7 + usat r7, #8, r7, asr #7 + strb r6, [r1], r2 ; the result is transposed back and stored + + add r8, r8, #0x40 ; round_shift_and_clamp + strb r7, [r1], r2 + add r9, r9, #0x40 + usat r8, #8, r8, asr #7 + usat r9, #8, r9, asr #7 + strb r8, [r1], r2 ; the result is transposed back and stored + + ldrne r6, [r0] ; load data + strb r9, [r1], r2 + ldrne r8, [r0, #4] + ldrneh r10, [r0, #8] + + bne bil_width_loop_2nd + + subs r12, r12, #1 + add r0, r0, #4 ; update src for next row + add r11, r11, #1 + mov r1, r11 + + bne bil_height_loop_2nd + ldmia sp!, {r4 - r11, pc} + +|bil_null_2nd_filter| +|bil_height_loop_null_2nd| + mov lr, r3, lsr #2 + +|bil_width_loop_null_2nd| + ldr r6, [r0], #4 ; load data + subs lr, lr, #1 + ldr r8, [r0], #4 + + strb r6, [r1], r2 ; store data + mov r7, r6, lsr #16 + strb r7, [r1], r2 + mov r9, r8, lsr #16 + strb r8, [r1], r2 + strb r9, [r1], r2 + + bne bil_width_loop_null_2nd + + subs r12, r12, #1 + add r0, r0, #4 + add r11, r11, #1 + mov r1, r11 + + bne bil_height_loop_null_2nd + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_second_pass_armv6| + + END
diff --git a/vp8/common/arm/armv6/copymem16x16_v6.asm b/vp8/common/arm/armv6/copymem16x16_v6.asm new file mode 100644 index 0000000..00e9739 --- /dev/null +++ b/vp8/common/arm/armv6/copymem16x16_v6.asm
@@ -0,0 +1,181 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem16x16_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem16x16_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem16x16_v6| PROC + stmdb sp!, {r4 - r7} + ;push {r4-r7} + + ;preload + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + ands r4, r0, #15 + beq copy_mem16x16_fast + + ands r4, r0, #7 + beq copy_mem16x16_8 + + ands r4, r0, #3 + beq copy_mem16x16_4 + + ;copy one byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + ldrb r6, [r0, #2] + ldrb r7, [r0, #3] + + mov r12, #16 + +copy_mem16x16_1_loop + strb r4, [r2] + strb r5, [r2, #1] + strb r6, [r2, #2] + strb r7, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + ldrb r6, [r0, #6] + ldrb r7, [r0, #7] + + subs r12, r12, #1 + + strb r4, [r2, #4] + strb r5, [r2, #5] + strb r6, [r2, #6] + strb r7, [r2, #7] + + ldrb r4, [r0, #8] + ldrb r5, [r0, #9] + ldrb r6, [r0, #10] + ldrb r7, [r0, #11] + + strb r4, [r2, #8] + strb r5, [r2, #9] + strb r6, [r2, #10] + strb r7, [r2, #11] + + ldrb r4, [r0, #12] + ldrb r5, [r0, #13] + ldrb r6, [r0, #14] + ldrb r7, [r0, #15] + + add r0, r0, r1 + + strb r4, [r2, #12] + strb r5, [r2, #13] + strb r6, [r2, #14] + strb r7, [r2, #15] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + ldrneb r6, [r0, #2] + ldrneb r7, [r0, #3] + + bne copy_mem16x16_1_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 4 bytes each time +copy_mem16x16_4 + ldr r4, [r0] + ldr r5, [r0, #4] + ldr r6, [r0, #8] + ldr r7, [r0, #12] + + mov r12, #16 + +copy_mem16x16_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + str r6, [r2, #8] + str r7, [r2, #12] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + ldrne r6, [r0, #8] + ldrne r7, [r0, #12] + + bne copy_mem16x16_4_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 8 bytes each time +copy_mem16x16_8 + sub r1, r1, #16 + sub r3, r3, #16 + + mov r12, #16 + +copy_mem16x16_8_loop + ldmia r0!, {r4-r5} + ;ldm r0, {r4-r5} + ldmia r0!, {r6-r7} + + add r0, r0, r1 + + stmia r2!, {r4-r5} + subs r12, r12, #1 + ;stm r2, {r4-r5} + stmia r2!, {r6-r7} + + add r2, r2, r3 + + bne copy_mem16x16_8_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + +;copy 16 bytes each time +copy_mem16x16_fast + ;sub r1, r1, #16 + ;sub r3, r3, #16 + + mov r12, #16 + +copy_mem16x16_fast_loop + ldmia r0, {r4-r7} + ;ldm r0, {r4-r7} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r7} + ;stm r2, {r4-r7} + add r2, r2, r3 + + bne copy_mem16x16_fast_loop + + ldmia sp!, {r4 - r7} + ;pop {r4-r7} + mov pc, lr + + ENDP ; |vp8_copy_mem16x16_v6| + + END
diff --git a/vp8/common/arm/armv6/copymem8x4_v6.asm b/vp8/common/arm/armv6/copymem8x4_v6.asm new file mode 100644 index 0000000..94473ca --- /dev/null +++ b/vp8/common/arm/armv6/copymem8x4_v6.asm
@@ -0,0 +1,127 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x4_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void vp8_copy_mem8x4_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x4_v6| PROC + ;push {r4-r5} + stmdb sp!, {r4-r5} + + ;preload + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + ands r4, r0, #7 + beq copy_mem8x4_fast + + ands r4, r0, #3 + beq copy_mem8x4_4 + + ;copy 1 byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + + mov r12, #4 + +copy_mem8x4_1_loop + strb r4, [r2] + strb r5, [r2, #1] + + ldrb r4, [r0, #2] + ldrb r5, [r0, #3] + + subs r12, r12, #1 + + strb r4, [r2, #2] + strb r5, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + + strb r4, [r2, #4] + strb r5, [r2, #5] + + ldrb r4, [r0, #6] + ldrb r5, [r0, #7] + + add r0, r0, r1 + + strb r4, [r2, #6] + strb r5, [r2, #7] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + + bne copy_mem8x4_1_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 4 bytes each time +copy_mem8x4_4 + ldr r4, [r0] + ldr r5, [r0, #4] + + mov r12, #4 + +copy_mem8x4_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + + bne copy_mem8x4_4_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + +;copy 8 bytes each time +copy_mem8x4_fast + ;sub r1, r1, #8 + ;sub r3, r3, #8 + + mov r12, #4 + +copy_mem8x4_fast_loop + ldmia r0, {r4-r5} + ;ldm r0, {r4-r5} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r5} + ;stm r2, {r4-r5} + add r2, r2, r3 + + bne copy_mem8x4_fast_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + + ENDP ; |vp8_copy_mem8x4_v6| + + END
diff --git a/vp8/common/arm/armv6/copymem8x8_v6.asm b/vp8/common/arm/armv6/copymem8x8_v6.asm new file mode 100644 index 0000000..7cfa533 --- /dev/null +++ b/vp8/common/arm/armv6/copymem8x8_v6.asm
@@ -0,0 +1,127 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x8_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x8_v6( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x8_v6| PROC + ;push {r4-r5} + stmdb sp!, {r4-r5} + + ;preload + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + ands r4, r0, #7 + beq copy_mem8x8_fast + + ands r4, r0, #3 + beq copy_mem8x8_4 + + ;copy 1 byte each time + ldrb r4, [r0] + ldrb r5, [r0, #1] + + mov r12, #8 + +copy_mem8x8_1_loop + strb r4, [r2] + strb r5, [r2, #1] + + ldrb r4, [r0, #2] + ldrb r5, [r0, #3] + + subs r12, r12, #1 + + strb r4, [r2, #2] + strb r5, [r2, #3] + + ldrb r4, [r0, #4] + ldrb r5, [r0, #5] + + strb r4, [r2, #4] + strb r5, [r2, #5] + + ldrb r4, [r0, #6] + ldrb r5, [r0, #7] + + add r0, r0, r1 + + strb r4, [r2, #6] + strb r5, [r2, #7] + + add r2, r2, r3 + + ldrneb r4, [r0] + ldrneb r5, [r0, #1] + + bne copy_mem8x8_1_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 4 bytes each time +copy_mem8x8_4 + ldr r4, [r0] + ldr r5, [r0, #4] + + mov r12, #8 + +copy_mem8x8_4_loop + subs r12, r12, #1 + add r0, r0, r1 + + str r4, [r2] + str r5, [r2, #4] + + add r2, r2, r3 + + ldrne r4, [r0] + ldrne r5, [r0, #4] + + bne copy_mem8x8_4_loop + + ldmia sp!, {r4 - r5} + ;pop {r4-r5} + mov pc, lr + +;copy 8 bytes each time +copy_mem8x8_fast + ;sub r1, r1, #8 + ;sub r3, r3, #8 + + mov r12, #8 + +copy_mem8x8_fast_loop + ldmia r0, {r4-r5} + ;ldm r0, {r4-r5} + add r0, r0, r1 + + subs r12, r12, #1 + stmia r2, {r4-r5} + ;stm r2, {r4-r5} + add r2, r2, r3 + + bne copy_mem8x8_fast_loop + + ldmia sp!, {r4-r5} + ;pop {r4-r5} + mov pc, lr + + ENDP ; |vp8_copy_mem8x8_v6| + + END
diff --git a/vp8/common/arm/armv6/filter_v6.asm b/vp8/common/arm/armv6/filter_v6.asm new file mode 100644 index 0000000..a7863fc --- /dev/null +++ b/vp8/common/arm/armv6/filter_v6.asm
@@ -0,0 +1,383 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_filter_block2d_first_pass_armv6| + EXPORT |vp8_filter_block2d_second_pass_armv6| + EXPORT |vp8_filter_block2d_first_pass_only_armv6| + EXPORT |vp8_filter_block2d_second_pass_only_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------------- +; r0 unsigned char *src_ptr +; r1 short *output_ptr +; r2 unsigned int src_pixels_per_line +; r3 unsigned int output_width +; stack unsigned int output_height +; stack const short *vp8_filter +;------------------------------------- +; vp8_filter the input and put in the output array. Apply the 6 tap FIR filter with +; the output being a 2 byte value and the intput being a 1 byte value. +|vp8_filter_block2d_first_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; vp8_filter address + ldr r7, [sp, #36] ; output height + + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + mov r3, r3, lsl #1 ; multiply width by 2 because using shorts + add r12, r3, #16 ; square off the output + sub sp, sp, #4 + + ;;IF ARCHITECTURE=6 + ;pld [r0, #-2] + ;;pld [r0, #30] + ;;ENDIF + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r1, [sp] ; push destination to stack + mov r7, r7, lsl #16 ; height is top part of counter + +; six tap filter +|height_loop_1st_6| + ldrb r8, [r0, #-2] ; load source data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + orr r7, r7, r3, lsr #2 ; construct loop counter + +|width_loop_1st_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + + smuad lr, lr, r4 ; apply the filter + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + sub r7, r7, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r11, r10, r6, r8 + + ands r10, r7, #0xff ; test loop counter + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 + add r11, r11, #0x40 + ldrneb r9, [r0, #-1] + usat r11, #8, r11, asr #7 + + strh lr, [r1], r12 ; result is transposed and stored, which + ; will make second pass filtering easier. + ldrneb r10, [r0], #2 + strh r11, [r1], r12 + + bne width_loop_1st_6 + + ;;add r9, r2, #30 ; attempt to load 2 adjacent cache lines + ;;IF ARCHITECTURE=6 + ;pld [r0, r2] + ;;pld [r0, r9] + ;;ENDIF + + ldr r1, [sp] ; load and update dst address + subs r7, r7, #0x10000 + add r0, r0, r2 ; move to next input line + add r1, r1, #2 ; move over to next column + str r1, [sp] + + bne height_loop_1st_6 + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +;--------------------------------- +; r0 short *src_ptr, +; r1 unsigned char *output_ptr, +; r2 unsigned int output_pitch, +; r3 unsigned int cnt, +; stack const short *vp8_filter +;--------------------------------- +|vp8_filter_block2d_second_pass_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #36] ; vp8_filter address + sub sp, sp, #4 + mov r7, r3, lsl #16 ; height is top part of counter + str r1, [sp] ; push destination to stack + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + pkhbt r12, r5, r4 ; pack the filter differently + pkhbt r11, r6, r5 + + sub r0, r0, #4 ; offset input buffer + +|height_loop_2nd| + ldr r8, [r0] ; load the data + ldr r9, [r0, #4] + orr r7, r7, r3, lsr #1 ; loop counter + +|width_loop_2nd| + smuad lr, r4, r8 ; apply filter + sub r7, r7, #1 + smulbt r8, r4, r8 + + ldr r10, [r0, #8] + + smlad lr, r5, r9, lr + smladx r8, r12, r9, r8 + + ldrh r9, [r0, #12] + + smlad lr, r6, r10, lr + smladx r8, r11, r10, r8 + + add r0, r0, #4 + smlatb r10, r6, r9, r8 + + add lr, lr, #0x40 ; round_shift_and_clamp + ands r8, r7, #0xff + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r1], r2 ; the result is transposed back and stored + usat r10, #8, r10, asr #7 + + ldrne r8, [r0] ; load data for next loop + ldrne r9, [r0, #4] + strb r10, [r1], r2 + + bne width_loop_2nd + + ldr r1, [sp] ; update dst for next loop + subs r7, r7, #0x10000 + add r0, r0, #16 ; updata src for next loop + add r1, r1, #1 + str r1, [sp] + + bne height_loop_2nd + + add sp, sp, #4 + ldmia sp!, {r4 - r11, pc} + + ENDP + +;------------------------------------ +; r0 unsigned char *src_ptr +; r1 unsigned char *output_ptr, +; r2 unsigned int src_pixels_per_line +; r3 unsigned int cnt, +; stack unsigned int output_pitch, +; stack const short *vp8_filter +;------------------------------------ +|vp8_filter_block2d_first_pass_only_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r4, [sp, #36] ; output pitch + ldr r11, [sp, #40] ; HFilter address + sub sp, sp, #8 + + mov r7, r3 + sub r2, r2, r3 ; inside loop increments input array, + ; so the height loop only needs to add + ; r2 - width to the input pointer + + sub r4, r4, r3 + str r4, [sp] ; save modified output pitch + str r2, [sp, #4] + + mov r2, #0x40 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + +; six tap filter +|height_loop_1st_only_6| + ldrb r8, [r0, #-2] ; load data + ldrb r9, [r0, #-1] + ldrb r10, [r0], #2 + + mov r12, r3, lsr #1 ; loop counter + +|width_loop_1st_only_6| + ldrb r11, [r0, #-1] + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0] + +;; smuad lr, lr, r4 + smlad lr, lr, r4, r2 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 +;; smuad r8, r8, r4 + smlad r8, r8, r4, r2 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0, #1] + smlad r8, r11, r5, r8 + ldrb r11, [r0, #2] + + subs r12, r12, #1 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r10, r10, r6, r8 + +;; add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0, #-2] ; load data for next loop + usat lr, #8, lr, asr #7 +;; add r10, r10, #0x40 + strb lr, [r1], #1 ; store the result + usat r10, #8, r10, asr #7 + + ldrneb r9, [r0, #-1] + strb r10, [r1], #1 + ldrneb r10, [r0], #2 + + bne width_loop_1st_only_6 + + ;;add r9, r2, #30 ; attempt to load 2 adjacent cache lines + ;;IF ARCHITECTURE=6 + ;pld [r0, r2] + ;;pld [r0, r9] + ;;ENDIF + + ldr lr, [sp] ; load back output pitch + ldr r12, [sp, #4] ; load back output pitch + subs r7, r7, #1 + add r0, r0, r12 ; updata src for next loop + add r1, r1, lr ; update dst for next loop + + bne height_loop_1st_only_6 + + add sp, sp, #8 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_first_pass_only_armv6| + + +;------------------------------------ +; r0 unsigned char *src_ptr, +; r1 unsigned char *output_ptr, +; r2 unsigned int src_pixels_per_line +; r3 unsigned int cnt, +; stack unsigned int output_pitch, +; stack const short *vp8_filter +;------------------------------------ +|vp8_filter_block2d_second_pass_only_armv6| PROC + stmdb sp!, {r4 - r11, lr} + + ldr r11, [sp, #40] ; VFilter address + ldr r12, [sp, #36] ; output pitch + + mov r7, r3, lsl #16 ; height is top part of counter + sub r0, r0, r2, lsl #1 ; need 6 elements for filtering, 2 before, 3 after + + sub sp, sp, #8 + + ldr r4, [r11] ; load up packed filter coefficients + ldr r5, [r11, #4] + ldr r6, [r11, #8] + + str r0, [sp] ; save r0 to stack + str r1, [sp, #4] ; save dst to stack + +; six tap filter +|width_loop_2nd_only_6| + ldrb r8, [r0], r2 ; load data + orr r7, r7, r3 ; loop counter + ldrb r9, [r0], r2 + ldrb r10, [r0], r2 + +|height_loop_2nd_only_6| + ; filter first column in this inner loop, than, move to next colum. + ldrb r11, [r0], r2 + + pkhbt lr, r8, r9, lsl #16 ; r9 | r8 + pkhbt r8, r9, r10, lsl #16 ; r10 | r9 + + ldrb r9, [r0], r2 + + smuad lr, lr, r4 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + smuad r8, r8, r4 + pkhbt r11, r11, r9, lsl #16 ; r9 | r11 + + smlad lr, r10, r5, lr + ldrb r10, [r0], r2 + smlad r8, r11, r5, r8 + ldrb r11, [r0] + + sub r7, r7, #2 + sub r0, r0, r2, lsl #2 + + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + pkhbt r10, r10, r11, lsl #16 ; r11 | r10 + + smlad lr, r9, r6, lr + smlad r10, r10, r6, r8 + + ands r9, r7, #0xff + + add lr, lr, #0x40 ; round_shift_and_clamp + ldrneb r8, [r0], r2 ; load data for next loop + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r1], r12 ; store the result for the column + usat r10, #8, r10, asr #7 + + ldrneb r9, [r0], r2 + strb r10, [r1], r12 + ldrneb r10, [r0], r2 + + bne height_loop_2nd_only_6 + + ldr r0, [sp] + ldr r1, [sp, #4] + subs r7, r7, #0x10000 + add r0, r0, #1 ; move to filter next column + str r0, [sp] + add r1, r1, #1 + str r1, [sp, #4] + + bne width_loop_2nd_only_6 + + add sp, sp, #8 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_filter_block2d_second_pass_only_armv6| + + END
diff --git a/vp8/common/arm/armv6/idct_v6.asm b/vp8/common/arm/armv6/idct_v6.asm new file mode 100644 index 0000000..25c5165 --- /dev/null +++ b/vp8/common/arm/armv6/idct_v6.asm
@@ -0,0 +1,376 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +; r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r14 + EXPORT |vp8_short_idct4x4llm_1_v6| + EXPORT |vp8_short_idct4x4llm_v6| + EXPORT |vp8_short_idct4x4llm_v6_scott| + EXPORT |vp8_short_idct4x4llm_v6_dual| + + EXPORT |vp8_dc_only_idct_armv6| + + AREA |.text|, CODE, READONLY + +;******************************************************************************** +;* void short_idct4x4llm_1_v6(INT16 * input, INT16 * output, INT32 pitch) +;* r0 INT16 * input +;* r1 INT16 * output +;* r2 INT32 pitch +;* bench: 3/5 +;******************************************************************************** + +|vp8_short_idct4x4llm_1_v6| PROC ; cycles in out pit + ; + ldrsh r0, [r0] ; load input[0] 1, r0 un 2 + add r0, r0, #4 ; 1 +4 + stmdb sp!, {r4, r5, lr} ; make room for wide writes 1 backup + mov r0, r0, asr #3 ; (input[0] + 4) >> 3 1, r0 req`d ^1 >> 3 + pkhbt r4, r0, r0, lsl #16 ; pack r0 into r4 1, r0 req`d ^1 pack + mov r5, r4 ; expand expand + + strd r4, [r1], r2 ; *output = r0, post inc 1 + strd r4, [r1], r2 ; 1 + strd r4, [r1], r2 ; 1 + strd r4, [r1] ; 1 + ; + ldmia sp!, {r4, r5, pc} ; replace vars, return restore + ENDP ; |vp8_short_idct4x4llm_1_v6| +;******************************************************************************** +;******************************************************************************** +;******************************************************************************** + +;******************************************************************************** +;* void short_idct4x4llm_v6(INT16 * input, INT16 * output, INT32 pitch) +;* r0 INT16 * input +;* r1 INT16 * output +;* r2 INT32 pitch +;* bench: +;******************************************************************************** + +|vp8_short_idct4x4llm_v6| PROC ; cycles in out pit + ; + stmdb sp!, {r4-r11, lr} ; backup registers 1 backup + ; + mov r4, #0x00004E00 ; 1 cst + orr r4, r4, #0x0000007B ; cospi8sqrt2minus1 + mov r5, #0x00008A00 ; 1 cst + orr r5, r5, #0x0000008C ; sinpi8sqrt2 + ; + mov r6, #4 ; i=4 1 i +loop1 ; + ldrsh r12, [r0, #8] ; input[4] 1, r12 unavail 2 [4] + ldrsh r3, [r0, #24] ; input[12] 1, r3 unavail 2 [12] + ldrsh r8, [r0, #16] ; input[8] 1, r8 unavail 2 [8] + ldrsh r7, [r0], #0x2 ; input[0] 1, r7 unavail 2 ++ [0] + smulwb r10, r5, r12 ; ([4] * sinpi8sqrt2) >> 16 1, r10 un 2, r12/r5 ^1 t1 + smulwb r11, r4, r3 ; ([12] * cospi8sqrt2minus1) >> 16 1, r11 un 2, r3/r4 ^1 t2 + add r9, r7, r8 ; a1 = [0] + [8] 1 a1 + sub r7, r7, r8 ; b1 = [0] - [8] 1 b1 + add r11, r3, r11 ; temp2 1 + rsb r11, r11, r10 ; c1 = temp1 - temp2 1 c1 + smulwb r3, r5, r3 ; ([12] * sinpi8sqrt2) >> 16 1, r3 un 2, r3/r5 ^ 1 t2 + smulwb r10, r4, r12 ; ([4] * cospi8sqrt2minus1) >> 16 1, r10 un 2, r12/r4 ^1 t1 + add r8, r7, r11 ; b1 + c1 1 b+c + strh r8, [r1, r2] ; out[pitch] = b1+c1 1 + sub r7, r7, r11 ; b1 - c1 1 b-c + add r10, r12, r10 ; temp1 1 + add r3, r10, r3 ; d1 = temp1 + temp2 1 d1 + add r10, r9, r3 ; a1 + d1 1 a+d + sub r3, r9, r3 ; a1 - d1 1 a-d + add r8, r2, r2 ; pitch * 2 1 p*2 + strh r7, [r1, r8] ; out[pitch*2] = b1-c1 1 + add r7, r2, r2, lsl #1 ; pitch * 3 1 p*3 + strh r3, [r1, r7] ; out[pitch*3] = a1-d1 1 + subs r6, r6, #1 ; i-- 1 -- + strh r10, [r1], #0x2 ; out[0] = a1+d1 1 ++ + bne loop1 ; if i>0, continue + ; + sub r1, r1, #8 ; set up out for next loop 1 -4 + ; for this iteration, input=prev output + mov r6, #4 ; i=4 1 i +; b returnfull +loop2 ; + ldrsh r11, [r1, #2] ; input[1] 1, r11 un 2 [1] + ldrsh r8, [r1, #6] ; input[3] 1, r8 un 2 [3] + ldrsh r3, [r1, #4] ; input[2] 1, r3 un 2 [2] + ldrsh r0, [r1] ; input[0] 1, r0 un 2 [0] + smulwb r9, r5, r11 ; ([1] * sinpi8sqrt2) >> 16 1, r9 un 2, r5/r11 ^1 t1 + smulwb r10, r4, r8 ; ([3] * cospi8sqrt2minus1) >> 16 1, r10 un 2, r4/r8 ^1 t2 + add r7, r0, r3 ; a1 = [0] + [2] 1 a1 + sub r0, r0, r3 ; b1 = [0] - [2] 1 b1 + add r10, r8, r10 ; temp2 1 + rsb r9, r10, r9 ; c1 = temp1 - temp2 1 c1 + smulwb r8, r5, r8 ; ([3] * sinpi8sqrt2) >> 16 1, r8 un 2, r5/r8 ^1 t2 + smulwb r10, r4, r11 ; ([1] * cospi8sqrt2minus1) >> 16 1, r10 un 2, r4/r11 ^1 t1 + add r3, r0, r9 ; b1+c1 1 b+c + add r3, r3, #4 ; b1+c1+4 1 +4 + add r10, r11, r10 ; temp1 1 + mov r3, r3, asr #3 ; b1+c1+4 >> 3 1, r3 ^1 >>3 + strh r3, [r1, #2] ; out[1] = b1+c1 1 + add r10, r10, r8 ; d1 = temp1 + temp2 1 d1 + add r3, r7, r10 ; a1+d1 1 a+d + add r3, r3, #4 ; a1+d1+4 1 +4 + sub r7, r7, r10 ; a1-d1 1 a-d + add r7, r7, #4 ; a1-d1+4 1 +4 + mov r3, r3, asr #3 ; a1+d1+4 >> 3 1, r3 ^1 >>3 + mov r7, r7, asr #3 ; a1-d1+4 >> 3 1, r7 ^1 >>3 + strh r7, [r1, #6] ; out[3] = a1-d1 1 + sub r0, r0, r9 ; b1-c1 1 b-c + add r0, r0, #4 ; b1-c1+4 1 +4 + subs r6, r6, #1 ; i-- 1 -- + mov r0, r0, asr #3 ; b1-c1+4 >> 3 1, r0 ^1 >>3 + strh r0, [r1, #4] ; out[2] = b1-c1 1 + strh r3, [r1], r2 ; out[0] = a1+d1 1 +; add r1, r1, r2 ; out += pitch 1 ++ + bne loop2 ; if i>0, continue +returnfull ; + ldmia sp!, {r4 - r11, pc} ; replace vars, return restore + ENDP + +;******************************************************************************** +;******************************************************************************** +;******************************************************************************** + +;******************************************************************************** +;* void short_idct4x4llm_v6_scott(INT16 * input, INT16 * output, INT32 pitch) +;* r0 INT16 * input +;* r1 INT16 * output +;* r2 INT32 pitch +;* bench: +;******************************************************************************** + +|vp8_short_idct4x4llm_v6_scott| PROC ; cycles in out pit +; mov r0, #0 ; +; ldr r0, [r0] ; + stmdb sp!, {r4 - r11, lr} ; backup registers 1 backup + ; + mov r3, #0x00004E00 ; cos + orr r3, r3, #0x0000007B ; cospi8sqrt2minus1 + mov r4, #0x00008A00 ; sin + orr r4, r4, #0x0000008C ; sinpi8sqrt2 + ; + mov r5, #0x2 ; i i + ; +short_idct4x4llm_v6_scott_loop1 ; + ldr r10, [r0, #(4*2)] ; i5 | i4 5,4 + ldr r11, [r0, #(12*2)] ; i13 | i12 13,12 + ; + smulwb r6, r4, r10 ; ((ip[4] * sinpi8sqrt2) >> 16) lt1 + smulwb r7, r3, r11 ; ((ip[12] * cospi8sqrt2minus1) >> 16) lt2 + ; + smulwb r12, r3, r10 ; ((ip[4] * cospi8sqrt2misu1) >> 16) l2t2 + smulwb r14, r4, r11 ; ((ip[12] * sinpi8sqrt2) >> 16) l2t1 + ; + add r6, r6, r7 ; partial c1 lt1-lt2 + add r12, r12, r14 ; partial d1 l2t2+l2t1 + ; + smulwt r14, r4, r10 ; ((ip[5] * sinpi8sqrt2) >> 16) ht1 + smulwt r7, r3, r11 ; ((ip[13] * cospi8sqrt2minus1) >> 16) ht2 + ; + smulwt r8, r3, r10 ; ((ip[5] * cospi8sqrt2minus1) >> 16) h2t1 + smulwt r9, r4, r11 ; ((ip[13] * sinpi8sqrt2) >> 16) h2t2 + ; + add r7, r14, r7 ; partial c1_2 ht1+ht2 + sub r8, r8, r9 ; partial d1_2 h2t1-h2t2 + ; + pkhbt r6, r6, r7, lsl #16 ; partial c1_2 | partial c1_1 pack + pkhbt r12, r12, r8, lsl #16 ; partial d1_2 | partial d1_1 pack + ; + usub16 r6, r6, r10 ; c1_2 | c1_1 c + uadd16 r12, r12, r11 ; d1_2 | d1_1 d + ; + ldr r10, [r0, #0] ; i1 | i0 1,0 + ldr r11, [r0, #(8*2)] ; i9 | i10 9,10 + ; +;;;;;; add r0, r0, #0x4 ; +4 +;;;;;; add r1, r1, #0x4 ; +4 + ; + uadd16 r8, r10, r11 ; i1 + i9 | i0 + i8 aka a1 a + usub16 r9, r10, r11 ; i1 - i9 | i0 - i8 aka b1 b + ; + uadd16 r7, r8, r12 ; a1 + d1 pair a+d + usub16 r14, r8, r12 ; a1 - d1 pair a-d + ; + str r7, [r1] ; op[0] = a1 + d1 + str r14, [r1, r2] ; op[pitch*3] = a1 - d1 + ; + add r0, r0, #0x4 ; op[pitch] = b1 + c1 ++ + add r1, r1, #0x4 ; op[pitch*2] = b1 - c1 ++ + ; + subs r5, r5, #0x1 ; -- + bne short_idct4x4llm_v6_scott_loop1 ; + ; + sub r1, r1, #16 ; reset output ptr + mov r5, #0x4 ; + mov r0, r1 ; input = output + ; +short_idct4x4llm_v6_scott_loop2 ; + ; + subs r5, r5, #0x1 ; + bne short_idct4x4llm_v6_scott_loop2 ; + ; + ldmia sp!, {r4 - r11, pc} ; + ENDP ; + ; +;******************************************************************************** +;******************************************************************************** +;******************************************************************************** + +;******************************************************************************** +;* void short_idct4x4llm_v6_dual(INT16 * input, INT16 * output, INT32 pitch) +;* r0 INT16 * input +;* r1 INT16 * output +;* r2 INT32 pitch +;* bench: +;******************************************************************************** + +|vp8_short_idct4x4llm_v6_dual| PROC ; cycles in out pit + ; + stmdb sp!, {r4-r11, lr} ; backup registers 1 backup + mov r3, #0x00004E00 ; cos + orr r3, r3, #0x0000007B ; cospi8sqrt2minus1 + mov r4, #0x00008A00 ; sin + orr r4, r4, #0x0000008C ; sinpi8sqrt2 + mov r5, #0x2 ; i=2 i +loop1_dual + ldr r6, [r0, #(4*2)] ; i5 | i4 5|4 + ldr r12, [r0, #(12*2)] ; i13 | i12 13|12 + ldr r14, [r0, #(8*2)] ; i9 | i8 9|8 + + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwb r7, r3, r6 ; (ip[4] * cospi8sqrt2minus1) >> 16 4c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwb r8, r4, r6 ; (ip[4] * sinpi8sqrt2) >> 16 4s + pkhbt r7, r7, r9, lsl #16 ; 5c | 4c + smulwt r11, r3, r12 ; (ip[13] * cospi8sqrt2minus1) >> 16 13c + pkhbt r8, r8, r10, lsl #16 ; 5s | 4s + uadd16 r6, r6, r7 ; 5c+5 | 4c+4 + smulwt r7, r4, r12 ; (ip[13] * sinpi8sqrt2) >> 16 13s + smulwb r9, r3, r12 ; (ip[12] * cospi8sqrt2minus1) >> 16 12c + smulwb r10, r4, r12 ; (ip[12] * sinpi8sqrt2) >> 16 12s + subs r5, r5, #0x1 ; i-- -- + pkhbt r9, r9, r11, lsl #16 ; 13c | 12c + ldr r11, [r0], #0x4 ; i1 | i0 ++ 1|0 + pkhbt r10, r10, r7, lsl #16 ; 13s | 12s + uadd16 r7, r12, r9 ; 13c+13 | 12c+12 + usub16 r7, r8, r7 ; c c + uadd16 r6, r6, r10 ; d d + uadd16 r10, r11, r14 ; a a + usub16 r8, r11, r14 ; b b + uadd16 r9, r10, r6 ; a+d a+d + usub16 r10, r10, r6 ; a-d a-d + uadd16 r6, r8, r7 ; b+c b+c + usub16 r7, r8, r7 ; b-c b-c + str r6, [r1, r2] ; o5 | o4 + add r6, r2, r2 ; pitch * 2 p2 + str r7, [r1, r6] ; o9 | o8 + add r6, r6, r2 ; pitch * 3 p3 + str r10, [r1, r6] ; o13 | o12 + str r9, [r1], #0x4 ; o1 | o0 ++ + bne loop1_dual ; + mov r5, #0x2 ; i=2 i + sub r0, r1, #8 ; reset input/output i/o +loop2_dual + ldr r6, [r0, r2] ; i5 | i4 5|4 + ldr r1, [r0] ; i1 | i0 1|0 + ldr r12, [r0, #0x4] ; i3 | i2 3|2 + add r14, r2, #0x4 ; pitch + 2 p+2 + ldr r14, [r0, r14] ; i7 | i6 7|6 + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwt r7, r3, r1 ; (ip[1] * cospi8sqrt2minus1) >> 16 1c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwt r8, r4, r1 ; (ip[1] * sinpi8sqrt2) >> 16 1s + pkhbt r11, r6, r1, lsl #16 ; i0 | i4 0|4 + pkhbt r7, r9, r7, lsl #16 ; 1c | 5c + pkhbt r8, r10, r8, lsl #16 ; 1s | 5s = temp1 © tc1 + pkhtb r1, r1, r6, asr #16 ; i1 | i5 1|5 + uadd16 r1, r7, r1 ; 1c+1 | 5c+5 = temp2 (d) td2 + pkhbt r9, r14, r12, lsl #16 ; i2 | i6 2|6 + uadd16 r10, r11, r9 ; a a + usub16 r9, r11, r9 ; b b + pkhtb r6, r12, r14, asr #16 ; i3 | i7 3|7 + subs r5, r5, #0x1 ; i-- -- + smulwt r7, r3, r6 ; (ip[3] * cospi8sqrt2minus1) >> 16 3c + smulwt r11, r4, r6 ; (ip[3] * sinpi8sqrt2) >> 16 3s + smulwb r12, r3, r6 ; (ip[7] * cospi8sqrt2minus1) >> 16 7c + smulwb r14, r4, r6 ; (ip[7] * sinpi8sqrt2) >> 16 7s + + pkhbt r7, r12, r7, lsl #16 ; 3c | 7c + pkhbt r11, r14, r11, lsl #16 ; 3s | 7s = temp1 (d) td1 + uadd16 r6, r7, r6 ; 3c+3 | 7c+7 = temp2 (c) tc2 + usub16 r12, r8, r6 ; c (o1 | o5) c + uadd16 r6, r11, r1 ; d (o3 | o7) d + uadd16 r7, r10, r6 ; a+d a+d + mov r8, #0x4 ; set up 4's 4 + orr r8, r8, #0x40000 ; 4|4 + usub16 r6, r10, r6 ; a-d a-d + uadd16 r6, r6, r8 ; a-d+4 3|7 + uadd16 r7, r7, r8 ; a+d+4 0|4 + uadd16 r10, r9, r12 ; b+c b+c + usub16 r1, r9, r12 ; b-c b-c + uadd16 r10, r10, r8 ; b+c+4 1|5 + uadd16 r1, r1, r8 ; b-c+4 2|6 + mov r8, r10, asr #19 ; o1 >> 3 + strh r8, [r0, #2] ; o1 + mov r8, r1, asr #19 ; o2 >> 3 + strh r8, [r0, #4] ; o2 + mov r8, r6, asr #19 ; o3 >> 3 + strh r8, [r0, #6] ; o3 + mov r8, r7, asr #19 ; o0 >> 3 + strh r8, [r0], r2 ; o0 +p + sxth r10, r10 ; + mov r8, r10, asr #3 ; o5 >> 3 + strh r8, [r0, #2] ; o5 + sxth r1, r1 ; + mov r8, r1, asr #3 ; o6 >> 3 + strh r8, [r0, #4] ; o6 + sxth r6, r6 ; + mov r8, r6, asr #3 ; o7 >> 3 + strh r8, [r0, #6] ; o7 + sxth r7, r7 ; + mov r8, r7, asr #3 ; o4 >> 3 + strh r8, [r0], r2 ; o4 +p +;;;;; subs r5, r5, #0x1 ; i-- -- + bne loop2_dual ; + ; + ldmia sp!, {r4 - r11, pc} ; replace vars, return restore + ENDP + + +; sjl added 10/17/08 +;void dc_only_idct_armv6(short input_dc, short *output, int pitch) +|vp8_dc_only_idct_armv6| PROC + stmdb sp!, {r4 - r6, lr} + + add r0, r0, #0x4 + add r4, r1, r2 ; output + shortpitch + mov r0, r0, ASR #0x3 ;aka a1 + add r5, r1, r2, LSL #1 ; output + shortpitch * 2 + pkhbt r0, r0, r0, lsl #16 ; a1 | a1 + add r6, r5, r2 ; output + shortpitch * 3 + + str r0, [r1, #0] + str r0, [r1, #4] + + str r0, [r4, #0] + str r0, [r4, #4] + + str r0, [r5, #0] + str r0, [r5, #4] + + str r0, [r6, #0] + str r0, [r6, #4] + + + ldmia sp!, {r4 - r6, pc} + + ENDP ; |vp8_dc_only_idct_armv6| + + END
diff --git a/vp8/common/arm/armv6/iwalsh_v6.asm b/vp8/common/arm/armv6/iwalsh_v6.asm new file mode 100644 index 0000000..8747568 --- /dev/null +++ b/vp8/common/arm/armv6/iwalsh_v6.asm
@@ -0,0 +1,151 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + EXPORT |vp8_short_inv_walsh4x4_armv6| + EXPORT |vp8_short_inv_walsh4x4_1_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_inv_walsh4x4_armv6(short *input, short *output) +|vp8_short_inv_walsh4x4_armv6| PROC + + stmdb sp!, {r4 - r11, lr} + + ldr r2, [r0], #4 ; [1 | 0] + ldr r3, [r0], #4 ; [3 | 2] + ldr r4, [r0], #4 ; [5 | 4] + ldr r5, [r0], #4 ; [7 | 6] + ldr r6, [r0], #4 ; [9 | 8] + ldr r7, [r0], #4 ; [11 | 10] + ldr r8, [r0], #4 ; [13 | 12] + ldr r9, [r0] ; [15 | 14] + + qadd16 r10, r2, r8 ; a1 [1+13 | 0+12] + qadd16 r11, r4, r6 ; b1 [5+9 | 4+8] + qsub16 r12, r4, r6 ; c1 [5-9 | 4-8] + qsub16 lr, r2, r8 ; d1 [1-13 | 0-12] + + qadd16 r2, r10, r11 ; a1 + b1 [1 | 0] + qadd16 r4, r12, lr ; c1 + d1 [5 | 4] + qsub16 r6, r10, r11 ; a1 - b1 [9 | 8] + qsub16 r8, lr, r12 ; d1 - c1 [13 | 12] + + qadd16 r10, r3, r9 ; a1 [3+15 | 2+14] + qadd16 r11, r5, r7 ; b1 [7+11 | 6+10] + qsub16 r12, r5, r7 ; c1 [7-11 | 6-10] + qsub16 lr, r3, r9 ; d1 [3-15 | 2-14] + + qadd16 r3, r10, r11 ; a1 + b1 [3 | 2] + qadd16 r5, r12, lr ; c1 + d1 [7 | 6] + qsub16 r7, r10, r11 ; a1 - b1 [11 | 10] + qsub16 r9, lr, r12 ; d1 - c1 [15 | 14] + + ; first transform complete + + qsubaddx r10, r2, r3 ; [c1|a1] [1-2 | 0+3] + qaddsubx r11, r2, r3 ; [b1|d1] [1+2 | 0-3] + qsubaddx r12, r4, r5 ; [c1|a1] [5-6 | 4+7] + qaddsubx lr, r4, r5 ; [b1|d1] [5+6 | 4-7] + + qaddsubx r2, r10, r11 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r3, r11, r10 ; [a2|d2] [b1+a1 | d1-c1] + ldr r10, c0x00030003 + qaddsubx r4, r12, lr ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r5, lr, r12 ; [a2|d2] [b1+a1 | d1-c1] + + qadd16 r2, r2, r10 ; [b2+3|c2+3] + qadd16 r3, r3, r10 ; [a2+3|d2+3] + qadd16 r4, r4, r10 ; [b2+3|c2+3] + qadd16 r5, r5, r10 ; [a2+3|d2+3] + + asr r12, r2, #3 ; [1 | x] + pkhtb r12, r12, r3, asr #19; [1 | 0] + lsl lr, r3, #16 ; [~3 | x] + lsl r2, r2, #16 ; [~2 | x] + asr lr, lr, #3 ; [3 | x] + pkhtb lr, lr, r2, asr #19 ; [3 | 2] + + asr r2, r4, #3 ; [5 | x] + pkhtb r2, r2, r5, asr #19 ; [5 | 4] + lsl r3, r5, #16 ; [~7 | x] + lsl r4, r4, #16 ; [~6 | x] + asr r3, r3, #3 ; [7 | x] + pkhtb r3, r3, r4, asr #19 ; [7 | 6] + + str r12, [r1], #4 + str lr, [r1], #4 + str r2, [r1], #4 + str r3, [r1], #4 + + qsubaddx r2, r6, r7 ; [c1|a1] [9-10 | 8+11] + qaddsubx r3, r6, r7 ; [b1|d1] [9+10 | 8-11] + qsubaddx r4, r8, r9 ; [c1|a1] [13-14 | 12+15] + qaddsubx r5, r8, r9 ; [b1|d1] [13+14 | 12-15] + + qaddsubx r6, r2, r3 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r7, r3, r2 ; [a2|d2] [b1+a1 | d1-c1] + qaddsubx r8, r4, r5 ; [b2|c2] [c1+d1 | a1-b1] + qaddsubx r9, r5, r4 ; [a2|d2] [b1+a1 | d1-c1] + + qadd16 r6, r6, r10 ; [b2+3|c2+3] + qadd16 r7, r7, r10 ; [a2+3|d2+3] + qadd16 r8, r8, r10 ; [b2+3|c2+3] + qadd16 r9, r9, r10 ; [a2+3|d2+3] + + asr r2, r6, #3 ; [9 | x] + pkhtb r2, r2, r7, asr #19 ; [9 | 8] + lsl r3, r7, #16 ; [~11| x] + lsl r4, r6, #16 ; [~10| x] + asr r3, r3, #3 ; [11 | x] + pkhtb r3, r3, r4, asr #19 ; [11 | 10] + + asr r4, r8, #3 ; [13 | x] + pkhtb r4, r4, r9, asr #19 ; [13 | 12] + lsl r5, r9, #16 ; [~15| x] + lsl r6, r8, #16 ; [~14| x] + asr r5, r5, #3 ; [15 | x] + pkhtb r5, r5, r6, asr #19 ; [15 | 14] + + str r2, [r1], #4 + str r3, [r1], #4 + str r4, [r1], #4 + str r5, [r1] + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_short_inv_walsh4x4_armv6| + + +;short vp8_short_inv_walsh4x4_1_armv6(short *input, short *output) +|vp8_short_inv_walsh4x4_1_armv6| PROC + + ldrsh r2, [r0] ; [0] + add r2, r2, #3 ; [0] + 3 + asr r2, r2, #3 ; a1 ([0]+3) >> 3 + lsl r2, r2, #16 ; [a1 | x] + orr r2, r2, r2, lsr #16 ; [a1 | a1] + + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1], #4 + str r2, [r1] + + bx lr + ENDP ; |vp8_short_inv_walsh4x4_1_armv6| + +; Constant Pool +c0x00030003 DCD 0x00030003 + END
diff --git a/vp8/common/arm/armv6/loopfilter_v6.asm b/vp8/common/arm/armv6/loopfilter_v6.asm new file mode 100644 index 0000000..c2b02dc --- /dev/null +++ b/vp8/common/arm/armv6/loopfilter_v6.asm
@@ -0,0 +1,1263 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_horizontal_edge_armv6| + EXPORT |vp8_mbloop_filter_horizontal_edge_armv6| + EXPORT |vp8_loop_filter_vertical_edge_armv6| + EXPORT |vp8_mbloop_filter_vertical_edge_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + + MACRO + TRANSPOSE_MATRIX $a0, $a1, $a2, $a3, $b0, $b1, $b2, $b3 + ; input: $a0, $a1, $a2, $a3; output: $b0, $b1, $b2, $b3 + ; a0: 03 02 01 00 + ; a1: 13 12 11 10 + ; a2: 23 22 21 20 + ; a3: 33 32 31 30 + ; b3 b2 b1 b0 + + uxtb16 $b1, $a1 ; xx 12 xx 10 + uxtb16 $b0, $a0 ; xx 02 xx 00 + uxtb16 $b3, $a3 ; xx 32 xx 30 + uxtb16 $b2, $a2 ; xx 22 xx 20 + orr $b1, $b0, $b1, lsl #8 ; 12 02 10 00 + orr $b3, $b2, $b3, lsl #8 ; 32 22 30 20 + + uxtb16 $a1, $a1, ror #8 ; xx 13 xx 11 + uxtb16 $a3, $a3, ror #8 ; xx 33 xx 31 + uxtb16 $a0, $a0, ror #8 ; xx 03 xx 01 + uxtb16 $a2, $a2, ror #8 ; xx 23 xx 21 + orr $a0, $a0, $a1, lsl #8 ; 13 03 11 01 + orr $a2, $a2, $a3, lsl #8 ; 33 23 31 21 + + pkhtb $b2, $b3, $b1, asr #16 ; 32 22 12 02 -- p1 + pkhbt $b0, $b1, $b3, lsl #16 ; 30 20 10 00 -- p3 + + pkhtb $b3, $a2, $a0, asr #16 ; 33 23 13 03 -- p0 + pkhbt $b1, $a0, $a2, lsl #16 ; 31 21 11 01 -- p2 + MEND + + +src RN r0 +pstep RN r1 +count RN r5 + +;r0 unsigned char *src_ptr, +;r1 int src_pixel_step, +;r2 const char *flimit, +;r3 const char *limit, +;stack const char *thresh, +;stack int count + +;Note: All 16 elements in flimit are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r6, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r9, [src], pstep ; p3 + ldr r4, [r2], #4 ; flimit + ldr r10, [src], pstep ; p2 + ldr r2, [r3], #4 ; limit + ldr r11, [src], pstep ; p1 + uadd8 r4, r4, r4 ; flimit * 2 + ldr r3, [r6], #4 ; thresh + mov count, count, lsl #1 ; 4-in-parallel + uadd8 r4, r4, r2 ; flimit * 2 + limit + +|Hnext8| + ; vp8_filter_mask() function + ; calculate breakout conditions + ldr r12, [src], pstep ; p0 + + uqsub8 r6, r9, r10 ; p3 - p2 + uqsub8 r7, r10, r9 ; p2 - p3 + uqsub8 r8, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + + orr r6, r6, r7 ; abs (p3-p2) + orr r8, r8, r10 ; abs (p2-p1) + uqsub8 lr, r6, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r8, r8, r2 ; compare to limit + uqsub8 r6, r11, r12 ; p1 - p0 + orr lr, lr, r8 + uqsub8 r7, r12, r11 ; p0 - p1 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + orr r6, r6, r7 ; abs (p1-p0) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r8, r6, r3 ; compare to thresh -- save r8 for later + orr lr, lr, r7 + + uqsub8 r6, r11, r10 ; p1 - q1 + uqsub8 r7, r10, r11 ; q1 - p1 + uqsub8 r11, r12, r9 ; p0 - q0 + uqsub8 r12, r9, r12 ; q0 - p0 + orr r6, r6, r7 ; abs (p1-q1) + ldr r7, c0x7F7F7F7F + orr r12, r11, r12 ; abs (p0-q0) + ldr r11, [src], pstep ; q2 + uqadd8 r12, r12, r12 ; abs (p0-q0) * 2 + and r6, r7, r6, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r7, r9, r10 ; q0 - q1 + uqadd8 r12, r12, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r6, r10, r9 ; q1 - q0 + uqsub8 r12, r12, r4 ; compare to flimit + uqsub8 r9, r11, r10 ; q2 - q1 + + orr lr, lr, r12 + + ldr r12, [src], pstep ; q3 + uqsub8 r10, r10, r11 ; q1 - q2 + orr r6, r7, r6 ; abs (q1-q0) + orr r10, r9, r10 ; abs (q2-q1) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r10, r10, r2 ; compare to limit + uqsub8 r6, r6, r3 ; compare to thresh -- save r6 for later + orr lr, lr, r7 + orr lr, lr, r10 + + uqsub8 r10, r12, r11 ; q3 - q2 + uqsub8 r9, r11, r12 ; q2 - q3 + + mvn r11, #0 ; r11 == -1 + + orr r10, r10, r9 ; abs (q3-q2) + uqsub8 r10, r10, r2 ; compare to limit + + mov r12, #0 + orr lr, lr, r10 + sub src, src, pstep, lsl #2 + + usub8 lr, r12, lr ; use usub8 instead of ssub8 + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq hskip_filter ; skip filtering + + sub src, src, pstep, lsl #1 ; move src pointer down by 6 lines + + ;vp8_hevmask() function + ;calculate high edge variance + orr r10, r6, r8 ; calculate vp8_hevmask + + ldr r7, [src], pstep ; p1 + + usub8 r10, r12, r10 ; use usub8 instead of ssub8 + sel r6, r12, r11 ; obtain vp8_hevmask: r6 + + ;vp8_filter() function + ldr r8, [src], pstep ; p0 + ldr r12, c0x80808080 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + + eor r7, r7, r12 ; p1 offset to convert to a signed value + eor r8, r8, r12 ; p0 offset to convert to a signed value + eor r9, r9, r12 ; q0 offset to convert to a signed value + eor r10, r10, r12 ; q1 offset to convert to a signed value + + str r9, [sp] ; store qs0 temporarily + str r8, [sp, #4] ; store ps0 temporarily + str r10, [sp, #8] ; store qs1 temporarily + str r7, [sp, #12] ; store ps1 temporarily + + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + qsub8 r8, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + + and r7, r7, r6 ; vp8_filter (r7) &= hev + + qadd8 r7, r7, r8 + ldr r9, c0x03030303 ; r9 = 3 --modified for vp8 + + qadd8 r7, r7, r8 + ldr r10, c0x04040404 + + qadd8 r7, r7, r8 + and r7, r7, lr ; vp8_filter &= mask; + + ;modify code for vp8 -- Filter1 = vp8_filter (r7) + qadd8 r8 , r7 , r9 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r7 , r7 , r10 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + + mov r9, #0 + shadd8 r8 , r8 , r9 ; Filter2 >>= 3 + shadd8 r7 , r7 , r9 ; vp8_filter >>= 3 + shadd8 r8 , r8 , r9 + shadd8 r7 , r7 , r9 + shadd8 lr , r8 , r9 ; lr: Filter2 + shadd8 r7 , r7 , r9 ; r7: filter + + ;usub8 lr, r8, r10 ; s = (s==4)*-1 + ;sel lr, r11, r9 + ;usub8 r8, r10, r8 + ;sel r8, r11, r9 + ;and r8, r8, lr ; -1 for each element that equals 4 + + ;calculate output + ;qadd8 lr, r8, r7 ; u = vp8_signed_char_clamp(s + vp8_filter) + + ldr r8, [sp] ; load qs0 + ldr r9, [sp, #4] ; load ps0 + + ldr r10, c0x01010101 + + qsub8 r8 ,r8, r7 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) + qadd8 r9, r9, lr ; u = vp8_signed_char_clamp(ps0 + Filter2) + + ;end of modification for vp8 + + mov lr, #0 + sadd8 r7, r7 , r10 ; vp8_filter += 1 + shadd8 r7, r7, lr ; vp8_filter >>= 1 + + ldr r11, [sp, #12] ; load ps1 + ldr r10, [sp, #8] ; load qs1 + + bic r7, r7, r6 ; vp8_filter &= ~hev + sub src, src, pstep, lsl #2 + + qadd8 r11, r11, r7 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + qsub8 r10, r10,r7 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + + eor r11, r11, r12 ; *op1 = u^0x80 + str r11, [src], pstep ; store op1 + eor r9, r9, r12 ; *op0 = u^0x80 + str r9, [src], pstep ; store op0 result + eor r8, r8, r12 ; *oq0 = u^0x80 + str r8, [src], pstep ; store oq0 result + eor r10, r10, r12 ; *oq1 = u^0x80 + str r10, [src], pstep ; store oq1 + + sub src, src, pstep, lsl #1 + +|hskip_filter| + add src, src, #4 + sub src, src, pstep, lsl #2 + + subs count, count, #1 + + ;pld [src] + ;pld [src, pstep] + ;pld [src, pstep, lsl #1] + ;pld [src, pstep, lsl #2] + ;pld [src, pstep, lsl #3] + + ldrne r9, [src], pstep ; p3 + ldrne r10, [src], pstep ; p2 + ldrne r11, [src], pstep ; p1 + + bne Hnext8 + + add sp, sp, #16 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_mbloop_filter_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r6, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r9, [src], pstep ; p3 + ldr r4, [r2], #4 ; flimit + ldr r10, [src], pstep ; p2 + ldr r2, [r3], #4 ; limit + ldr r11, [src], pstep ; p1 + uadd8 r4, r4, r4 ; flimit * 2 + ldr r3, [r6], #4 ; thresh + mov count, count, lsl #1 ; 4-in-parallel + uadd8 r4, r4, r2 ; flimit * 2 + limit + +|MBHnext8| + + ; vp8_filter_mask() function + ; calculate breakout conditions + ldr r12, [src], pstep ; p0 + + uqsub8 r6, r9, r10 ; p3 - p2 + uqsub8 r7, r10, r9 ; p2 - p3 + uqsub8 r8, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + + orr r6, r6, r7 ; abs (p3-p2) + orr r8, r8, r10 ; abs (p2-p1) + uqsub8 lr, r6, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r8, r8, r2 ; compare to limit + + uqsub8 r6, r11, r12 ; p1 - p0 + orr lr, lr, r8 + uqsub8 r7, r12, r11 ; p0 - p1 + ldr r9, [src], pstep ; q0 + ldr r10, [src], pstep ; q1 + orr r6, r6, r7 ; abs (p1-p0) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r8, r6, r3 ; compare to thresh -- save r8 for later + orr lr, lr, r7 + + uqsub8 r6, r11, r10 ; p1 - q1 + uqsub8 r7, r10, r11 ; q1 - p1 + uqsub8 r11, r12, r9 ; p0 - q0 + uqsub8 r12, r9, r12 ; q0 - p0 + orr r6, r6, r7 ; abs (p1-q1) + ldr r7, c0x7F7F7F7F + orr r12, r11, r12 ; abs (p0-q0) + ldr r11, [src], pstep ; q2 + uqadd8 r12, r12, r12 ; abs (p0-q0) * 2 + and r6, r7, r6, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r7, r9, r10 ; q0 - q1 + uqadd8 r12, r12, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r6, r10, r9 ; q1 - q0 + uqsub8 r12, r12, r4 ; compare to flimit + uqsub8 r9, r11, r10 ; q2 - q1 + + orr lr, lr, r12 + + ldr r12, [src], pstep ; q3 + + uqsub8 r10, r10, r11 ; q1 - q2 + orr r6, r7, r6 ; abs (q1-q0) + orr r10, r9, r10 ; abs (q2-q1) + uqsub8 r7, r6, r2 ; compare to limit + uqsub8 r10, r10, r2 ; compare to limit + uqsub8 r6, r6, r3 ; compare to thresh -- save r6 for later + orr lr, lr, r7 + orr lr, lr, r10 + + uqsub8 r10, r12, r11 ; q3 - q2 + uqsub8 r9, r11, r12 ; q2 - q3 + + mvn r11, #0 ; r11 == -1 + + orr r10, r10, r9 ; abs (q3-q2) + uqsub8 r10, r10, r2 ; compare to limit + + mov r12, #0 + + orr lr, lr, r10 + + usub8 lr, r12, lr ; use usub8 instead of ssub8 + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq mbhskip_filter ; skip filtering + + ;vp8_hevmask() function + ;calculate high edge variance + sub src, src, pstep, lsl #2 ; move src pointer down by 6 lines + sub src, src, pstep, lsl #1 + + orr r10, r6, r8 + ldr r7, [src], pstep ; p1 + + usub8 r10, r12, r10 + sel r6, r12, r11 ; hev mask: r6 + + ;vp8_mbfilter() function + ;p2, q2 are only needed at the end. Don't need to load them in now. + ldr r8, [src], pstep ; p0 + ldr r12, c0x80808080 + ldr r9, [src], pstep ; q0 + ldr r10, [src] ; q1 + + eor r7, r7, r12 ; ps1 + eor r8, r8, r12 ; ps0 + eor r9, r9, r12 ; qs0 + eor r10, r10, r12 ; qs1 + + qsub8 r12, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + str r7, [sp, #12] ; store ps1 temporarily + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + str r10, [sp, #8] ; store qs1 temporarily + qadd8 r7, r7, r12 + str r9, [sp] ; store qs0 temporarily + qadd8 r7, r7, r12 + str r8, [sp, #4] ; store ps0 temporarily + qadd8 r7, r7, r12 ; vp8_filter: r7 + + ldr r10, c0x03030303 ; r10 = 3 --modified for vp8 + ldr r9, c0x04040404 + + and r7, r7, lr ; vp8_filter &= mask (lr is free) + + mov r12, r7 ; Filter2: r12 + and r12, r12, r6 ; Filter2 &= hev + + ;modify code for vp8 + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r12 , r9 ; Filter1 (r8) = vp8_signed_char_clamp(Filter2+4) + qadd8 r12 , r12 , r10 ; Filter2 (r12) = vp8_signed_char_clamp(Filter2+3) + + mov r10, #0 + shadd8 r8 , r8 , r10 ; Filter1 >>= 3 + shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + shadd8 r8 , r8 , r10 + shadd8 r12 , r12 , r10 + shadd8 r8 , r8 , r10 ; r8: Filter1 + shadd8 r12 , r12 , r10 ; r12: Filter2 + + ldr r9, [sp] ; load qs0 + ldr r11, [sp, #4] ; load ps0 + + qsub8 r9 , r9, r8 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + qadd8 r11, r11, r12 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) + + ;save bottom 3 bits so that we round one side +4 and the other +3 + ;and r8, r12, r10 ; s = Filter2 & 7 (s: r8) + ;qadd8 r12 , r12 , r9 ; Filter2 = vp8_signed_char_clamp(Filter2+4) + ;mov r10, #0 + ;shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + ;usub8 lr, r8, r9 ; s = (s==4)*-1 + ;sel lr, r11, r10 + ;shadd8 r12 , r12 , r10 + ;usub8 r8, r9, r8 + ;sel r8, r11, r10 + ;ldr r9, [sp] ; load qs0 + ;ldr r11, [sp, #4] ; load ps0 + ;shadd8 r12 , r12 , r10 + ;and r8, r8, lr ; -1 for each element that equals 4 + ;qadd8 r10, r8, r12 ; u = vp8_signed_char_clamp(s + Filter2) + ;qsub8 r9 , r9, r12 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) + ;qadd8 r11, r11, r10 ; ps0 = vp8_signed_char_clamp(ps0 + u) + + ;end of modification for vp8 + + bic r12, r7, r6 ; vp8_filter &= ~hev ( r6 is free) + ;mov r12, r7 + + ;roughly 3/7th difference across boundary + mov lr, #0x1b ; 27 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r7, r10, lr, r7 + smultb r10, r10, lr + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + add r10, r10, #63 + ssat r7, #8, r7, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r7, r10, lsl #16 + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs0 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps0 + u) + eor r8, r8, lr ; *oq0 = s^0x80 + str r8, [src] ; store *oq0 + sub src, src, pstep + eor r10, r10, lr ; *op0 = s^0x80 + str r10, [src] ; store *op0 + + ;roughly 2/7th difference across boundary + mov lr, #0x12 ; 18 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r9, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r9, #8, r9, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r9, r10, lsl #16 + + ldr r9, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + + qadd8 r11, r11, r10 ; s = vp8_signed_char_clamp(ps1 + u) + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs1 - u) + eor r11, r11, lr ; *op1 = s^0x80 + str r11, [src], pstep ; store *op1 + eor r8, r8, lr ; *oq1 = s^0x80 + add src, src, pstep, lsl #1 + + mov r7, #0x3f ; 63 + + str r8, [src], pstep ; store *oq1 + + ;roughly 1/7th difference across boundary + mov lr, #0x9 ; 9 + ldr r9, [src] ; load q2 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r12, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r12, #8, r12, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r12, r10, lsl #16 + + sub src, src, pstep + ldr lr, c0x80808080 + + ldr r11, [src] ; load p2 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + eor r9, r9, lr + eor r11, r11, lr + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + + qadd8 r8, r11, r10 ; s = vp8_signed_char_clamp(ps2 + u) + qsub8 r10, r9, r10 ; s = vp8_signed_char_clamp(qs2 - u) + eor r8, r8, lr ; *op2 = s^0x80 + str r8, [src], pstep, lsl #2 ; store *op2 + add src, src, pstep + eor r10, r10, lr ; *oq2 = s^0x80 + str r10, [src], pstep, lsl #1 ; store *oq2 + +|mbhskip_filter| + add src, src, #4 + sub src, src, pstep, lsl #3 + subs count, count, #1 + + ldrne r9, [src], pstep ; p3 + ldrne r10, [src], pstep ; p2 + ldrne r11, [src], pstep ; p1 + + bne MBHnext8 + + add sp, sp, #16 + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_mbloop_filter_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, #4 ; move src pointer down by 4 + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r12, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r6, [src], pstep ; load source data + ldr r4, [r2], #4 ; flimit + ldr r7, [src], pstep + ldr r2, [r3], #4 ; limit + ldr r8, [src], pstep + uadd8 r4, r4, r4 ; flimit * 2 + ldr r3, [r12], #4 ; thresh + ldr lr, [src], pstep + mov count, count, lsl #1 ; 4-in-parallel + uadd8 r4, r4, r2 ; flimit * 2 + limit + +|Vnext8| + + ; vp8_filter_mask() function + ; calculate breakout conditions + ; transpose the source data for 4-in-parallel operation + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + uqsub8 r7, r9, r10 ; p3 - p2 + uqsub8 r8, r10, r9 ; p2 - p3 + uqsub8 r9, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + orr r7, r7, r8 ; abs (p3-p2) + orr r10, r9, r10 ; abs (p2-p1) + uqsub8 lr, r7, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r10, r10, r2 ; compare to limit + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr lr, lr, r10 + + uqsub8 r6, r11, r12 ; p1 - p0 + uqsub8 r7, r12, r11 ; p0 - p1 + add src, src, #4 ; move src pointer up by 4 + orr r6, r6, r7 ; abs (p1-p0) + str r11, [sp, #12] ; save p1 + uqsub8 r10, r6, r2 ; compare to limit + uqsub8 r11, r6, r3 ; compare to thresh + orr lr, lr, r10 + + ; transpose uses 8 regs(r6 - r12 and lr). Need to save reg value now + ; transpose the source data for 4-in-parallel operation + ldr r6, [src], pstep ; load source data + str r11, [sp] ; push r11 to stack + ldr r7, [src], pstep + str r12, [sp, #4] ; save current reg before load q0 - q3 data + ldr r8, [src], pstep + str lr, [sp, #8] + ldr lr, [src], pstep + + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + ldr lr, [sp, #8] ; load back (f)limit accumulator + + uqsub8 r6, r12, r11 ; q3 - q2 + uqsub8 r7, r11, r12 ; q2 - q3 + uqsub8 r12, r11, r10 ; q2 - q1 + uqsub8 r11, r10, r11 ; q1 - q2 + orr r6, r6, r7 ; abs (q3-q2) + orr r7, r12, r11 ; abs (q2-q1) + uqsub8 r6, r6, r2 ; compare to limit + uqsub8 r7, r7, r2 ; compare to limit + ldr r11, [sp, #4] ; load back p0 + ldr r12, [sp, #12] ; load back p1 + orr lr, lr, r6 + orr lr, lr, r7 + + uqsub8 r6, r11, r9 ; p0 - q0 + uqsub8 r7, r9, r11 ; q0 - p0 + uqsub8 r8, r12, r10 ; p1 - q1 + uqsub8 r11, r10, r12 ; q1 - p1 + orr r6, r6, r7 ; abs (p0-q0) + ldr r7, c0x7F7F7F7F + orr r8, r8, r11 ; abs (p1-q1) + uqadd8 r6, r6, r6 ; abs (p0-q0) * 2 + and r8, r7, r8, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r11, r10, r9 ; q1 - q0 + uqadd8 r6, r8, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r12, r9, r10 ; q0 - q1 + uqsub8 r6, r6, r4 ; compare to flimit + + orr r9, r11, r12 ; abs (q1-q0) + uqsub8 r8, r9, r2 ; compare to limit + uqsub8 r10, r9, r3 ; compare to thresh + orr lr, lr, r6 + orr lr, lr, r8 + + mvn r11, #0 ; r11 == -1 + mov r12, #0 + + usub8 lr, r12, lr + ldr r9, [sp] ; load the compared result + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq vskip_filter ; skip filtering + + ;vp8_hevmask() function + ;calculate high edge variance + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r9, r9, r10 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + usub8 r9, r12, r9 + sel r6, r12, r11 ; hev mask: r6 + + ;vp8_filter() function + ; load soure data to r6, r11, r12, lr + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + pkhbt r12, r7, r8, lsl #16 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + pkhbt r11, r9, r10, lsl #16 + + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + ; Transpose needs 8 regs(r6 - r12, and lr). Save r6 and lr first + str r6, [sp] + str lr, [sp, #4] + + pkhbt r6, r7, r8, lsl #16 + pkhbt lr, r9, r10, lsl #16 + + ;transpose r12, r11, r6, lr to r7, r8, r9, r10 + TRANSPOSE_MATRIX r12, r11, r6, lr, r7, r8, r9, r10 + + ;load back hev_mask r6 and filter_mask lr + ldr r12, c0x80808080 + ldr r6, [sp] + ldr lr, [sp, #4] + + eor r7, r7, r12 ; p1 offset to convert to a signed value + eor r8, r8, r12 ; p0 offset to convert to a signed value + eor r9, r9, r12 ; q0 offset to convert to a signed value + eor r10, r10, r12 ; q1 offset to convert to a signed value + + str r9, [sp] ; store qs0 temporarily + str r8, [sp, #4] ; store ps0 temporarily + str r10, [sp, #8] ; store qs1 temporarily + str r7, [sp, #12] ; store ps1 temporarily + + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + qsub8 r8, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + + and r7, r7, r6 ; vp8_filter (r7) &= hev (r7 : filter) + + qadd8 r7, r7, r8 + ldr r9, c0x03030303 ; r9 = 3 --modified for vp8 + + qadd8 r7, r7, r8 + ldr r10, c0x04040404 + + qadd8 r7, r7, r8 + ;mvn r11, #0 ; r11 == -1 + + and r7, r7, lr ; vp8_filter &= mask + + ;modify code for vp8 -- Filter1 = vp8_filter (r7) + qadd8 r8 , r7 , r9 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r7 , r7 , r10 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + + mov r9, #0 + shadd8 r8 , r8 , r9 ; Filter2 >>= 3 + shadd8 r7 , r7 , r9 ; vp8_filter >>= 3 + shadd8 r8 , r8 , r9 + shadd8 r7 , r7 , r9 + shadd8 lr , r8 , r9 ; lr: filter2 + shadd8 r7 , r7 , r9 ; r7: filter + + ;usub8 lr, r8, r10 ; s = (s==4)*-1 + ;sel lr, r11, r9 + ;usub8 r8, r10, r8 + ;sel r8, r11, r9 + ;and r8, r8, lr ; -1 for each element that equals 4 -- r8: s + + ;calculate output + ;qadd8 lr, r8, r7 ; u = vp8_signed_char_clamp(s + vp8_filter) + + ldr r8, [sp] ; load qs0 + ldr r9, [sp, #4] ; load ps0 + + ldr r10, c0x01010101 + + qsub8 r8, r8, r7 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) + qadd8 r9, r9, lr ; u = vp8_signed_char_clamp(ps0 + Filter2) + ;end of modification for vp8 + + eor r8, r8, r12 + eor r9, r9, r12 + + mov lr, #0 + + sadd8 r7, r7, r10 + shadd8 r7, r7, lr + + ldr r10, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + + bic r7, r7, r6 ; r7: vp8_filter + + qsub8 r10 , r10, r7 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + qadd8 r11, r11, r7 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + eor r10, r10, r12 + eor r11, r11, r12 + + sub src, src, pstep, lsl #2 + + ;we can use TRANSPOSE_MATRIX macro to transpose output - input: q1, q0, p0, p1 + ;output is b0, b1, b2, b3 + ;b0: 03 02 01 00 + ;b1: 13 12 11 10 + ;b2: 23 22 21 20 + ;b3: 33 32 31 30 + ; p1 p0 q0 q1 + ; (a3 a2 a1 a0) + TRANSPOSE_MATRIX r11, r9, r8, r10, r6, r7, r12, lr + + strh r6, [src, #-2] ; store the result + mov r6, r6, lsr #16 + strh r6, [src], pstep + + strh r7, [src, #-2] + mov r7, r7, lsr #16 + strh r7, [src], pstep + + strh r12, [src, #-2] + mov r12, r12, lsr #16 + strh r12, [src], pstep + + strh lr, [src, #-2] + mov lr, lr, lsr #16 + strh lr, [src], pstep + +|vskip_filter| + sub src, src, #4 + subs count, count, #1 + + ldrne r6, [src], pstep ; load source data + ldrne r7, [src], pstep + ldrne r8, [src], pstep + ldrne lr, [src], pstep + + bne Vnext8 + + add sp, sp, #16 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_vertical_edge_armv6| + + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_mbloop_filter_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, #4 ; move src pointer down by 4 + ldr count, [sp, #40] ; count for 8-in-parallel + ldr r12, [sp, #36] ; load thresh address + sub sp, sp, #16 ; create temp buffer + + ldr r6, [src], pstep ; load source data + ldr r4, [r2], #4 ; flimit + ldr r7, [src], pstep + ldr r2, [r3], #4 ; limit + ldr r8, [src], pstep + uadd8 r4, r4, r4 ; flimit * 2 + ldr r3, [r12], #4 ; thresh + ldr lr, [src], pstep + mov count, count, lsl #1 ; 4-in-parallel + uadd8 r4, r4, r2 ; flimit * 2 + limit + +|MBVnext8| + ; vp8_filter_mask() function + ; calculate breakout conditions + ; transpose the source data for 4-in-parallel operation + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + uqsub8 r7, r9, r10 ; p3 - p2 + uqsub8 r8, r10, r9 ; p2 - p3 + uqsub8 r9, r10, r11 ; p2 - p1 + uqsub8 r10, r11, r10 ; p1 - p2 + orr r7, r7, r8 ; abs (p3-p2) + orr r10, r9, r10 ; abs (p2-p1) + uqsub8 lr, r7, r2 ; compare to limit. lr: vp8_filter_mask + uqsub8 r10, r10, r2 ; compare to limit + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr lr, lr, r10 + + uqsub8 r6, r11, r12 ; p1 - p0 + uqsub8 r7, r12, r11 ; p0 - p1 + add src, src, #4 ; move src pointer up by 4 + orr r6, r6, r7 ; abs (p1-p0) + str r11, [sp, #12] ; save p1 + uqsub8 r10, r6, r2 ; compare to limit + uqsub8 r11, r6, r3 ; compare to thresh + orr lr, lr, r10 + + ; transpose uses 8 regs(r6 - r12 and lr). Need to save reg value now + ; transpose the source data for 4-in-parallel operation + ldr r6, [src], pstep ; load source data + str r11, [sp] ; push r11 to stack + ldr r7, [src], pstep + str r12, [sp, #4] ; save current reg before load q0 - q3 data + ldr r8, [src], pstep + str lr, [sp, #8] + ldr lr, [src], pstep + + TRANSPOSE_MATRIX r6, r7, r8, lr, r9, r10, r11, r12 + + ldr lr, [sp, #8] ; load back (f)limit accumulator + + uqsub8 r6, r12, r11 ; q3 - q2 + uqsub8 r7, r11, r12 ; q2 - q3 + uqsub8 r12, r11, r10 ; q2 - q1 + uqsub8 r11, r10, r11 ; q1 - q2 + orr r6, r6, r7 ; abs (q3-q2) + orr r7, r12, r11 ; abs (q2-q1) + uqsub8 r6, r6, r2 ; compare to limit + uqsub8 r7, r7, r2 ; compare to limit + ldr r11, [sp, #4] ; load back p0 + ldr r12, [sp, #12] ; load back p1 + orr lr, lr, r6 + orr lr, lr, r7 + + uqsub8 r6, r11, r9 ; p0 - q0 + uqsub8 r7, r9, r11 ; q0 - p0 + uqsub8 r8, r12, r10 ; p1 - q1 + uqsub8 r11, r10, r12 ; q1 - p1 + orr r6, r6, r7 ; abs (p0-q0) + ldr r7, c0x7F7F7F7F + orr r8, r8, r11 ; abs (p1-q1) + uqadd8 r6, r6, r6 ; abs (p0-q0) * 2 + and r8, r7, r8, lsr #1 ; abs (p1-q1) / 2 + uqsub8 r11, r10, r9 ; q1 - q0 + uqadd8 r6, r8, r6 ; abs (p0-q0)*2 + abs (p1-q1)/2 + uqsub8 r12, r9, r10 ; q0 - q1 + uqsub8 r6, r6, r4 ; compare to flimit + + orr r9, r11, r12 ; abs (q1-q0) + uqsub8 r8, r9, r2 ; compare to limit + uqsub8 r10, r9, r3 ; compare to thresh + orr lr, lr, r6 + orr lr, lr, r8 + + mvn r11, #0 ; r11 == -1 + mov r12, #0 + + usub8 lr, r12, lr + ldr r9, [sp] ; load the compared result + sel lr, r11, r12 ; filter mask: lr + + cmp lr, #0 + beq mbvskip_filter ; skip filtering + + + ;vp8_hevmask() function + ;calculate high edge variance + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r9, r9, r10 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + usub8 r9, r12, r9 + sel r6, r12, r11 ; hev mask: r6 + + + ; vp8_mbfilter() function + ; p2, q2 are only needed at the end. Don't need to load them in now. + ; Transpose needs 8 regs(r6 - r12, and lr). Save r6 and lr first + ; load soure data to r6, r11, r12, lr + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + pkhbt r12, r7, r8, lsl #16 + + ldrh r7, [src, #-2] + ldrh r8, [src], pstep + + pkhbt r11, r9, r10, lsl #16 + + ldrh r9, [src, #-2] + ldrh r10, [src], pstep + + str r6, [sp] ; save r6 + str lr, [sp, #4] ; save lr + + pkhbt r6, r7, r8, lsl #16 + pkhbt lr, r9, r10, lsl #16 + + ;transpose r12, r11, r6, lr to p1, p0, q0, q1 + TRANSPOSE_MATRIX r12, r11, r6, lr, r7, r8, r9, r10 + + ;load back hev_mask r6 and filter_mask lr + ldr r12, c0x80808080 + ldr r6, [sp] + ldr lr, [sp, #4] + + eor r7, r7, r12 ; ps1 + eor r8, r8, r12 ; ps0 + eor r9, r9, r12 ; qs0 + eor r10, r10, r12 ; qs1 + + qsub8 r12, r9, r8 ; vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + str r7, [sp, #12] ; store ps1 temporarily + qsub8 r7, r7, r10 ; vp8_signed_char_clamp(ps1-qs1) + str r10, [sp, #8] ; store qs1 temporarily + qadd8 r7, r7, r12 + str r9, [sp] ; store qs0 temporarily + qadd8 r7, r7, r12 + str r8, [sp, #4] ; store ps0 temporarily + qadd8 r7, r7, r12 ; vp8_filter: r7 + + ldr r10, c0x03030303 ; r10 = 3 --modified for vp8 + ldr r9, c0x04040404 + ;mvn r11, #0 ; r11 == -1 + + and r7, r7, lr ; vp8_filter &= mask (lr is free) + + mov r12, r7 ; Filter2: r12 + and r12, r12, r6 ; Filter2 &= hev + + ;modify code for vp8 + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r12 , r9 ; Filter1 (r8) = vp8_signed_char_clamp(Filter2+4) + qadd8 r12 , r12 , r10 ; Filter2 (r12) = vp8_signed_char_clamp(Filter2+3) + + mov r10, #0 + shadd8 r8 , r8 , r10 ; Filter1 >>= 3 + shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + shadd8 r8 , r8 , r10 + shadd8 r12 , r12 , r10 + shadd8 r8 , r8 , r10 ; r8: Filter1 + shadd8 r12 , r12 , r10 ; r12: Filter2 + + ldr r9, [sp] ; load qs0 + ldr r11, [sp, #4] ; load ps0 + + qsub8 r9 , r9, r8 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + qadd8 r11, r11, r12 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) + + ;save bottom 3 bits so that we round one side +4 and the other +3 + ;and r8, r12, r10 ; s = Filter2 & 7 (s: r8) + ;qadd8 r12 , r12 , r9 ; Filter2 = vp8_signed_char_clamp(Filter2+4) + ;mov r10, #0 + ;shadd8 r12 , r12 , r10 ; Filter2 >>= 3 + ;usub8 lr, r8, r9 ; s = (s==4)*-1 + ;sel lr, r11, r10 + ;shadd8 r12 , r12 , r10 + ;usub8 r8, r9, r8 + ;sel r8, r11, r10 + ;ldr r9, [sp] ; load qs0 + ;ldr r11, [sp, #4] ; load ps0 + ;shadd8 r12 , r12 , r10 + ;and r8, r8, lr ; -1 for each element that equals 4 + ;qadd8 r10, r8, r12 ; u = vp8_signed_char_clamp(s + Filter2) + ;qsub8 r9 , r9, r12 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) + ;qadd8 r11, r11, r10 ; ps0 = vp8_signed_char_clamp(ps0 + u) + + ;end of modification for vp8 + + bic r12, r7, r6 ;vp8_filter &= ~hev ( r6 is free) + ;mov r12, r7 + + ;roughly 3/7th difference across boundary + mov lr, #0x1b ; 27 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r7, r10, lr, r7 + smultb r10, r10, lr + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + add r10, r10, #63 + ssat r7, #8, r7, asr #7 + ssat r10, #8, r10, asr #7 + + ldr lr, c0x80808080 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r7, r10, lsl #16 + uxtb16 r6, r6 + uxtb16 r10, r10 + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs0 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps0 + u) + eor r8, r8, lr ; *oq0 = s^0x80 + eor r10, r10, lr ; *op0 = s^0x80 + + strb r10, [src, #-1] ; store op0 result + strb r8, [src], pstep ; store oq0 result + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + strb r10, [src, #-1] + strb r8, [src], pstep + + ;roughly 2/7th difference across boundary + mov lr, #0x12 ; 18 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r9, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r9, #8, r9, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 ; move src pointer down by 4 lines + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r9, r10, lsl #16 + + ldr r9, [sp, #8] ; load qs1 + ldr r11, [sp, #12] ; load ps1 + ldr lr, c0x80808080 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + add src, src, #2 + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + + qsub8 r8, r9, r10 ; s = vp8_signed_char_clamp(qs1 - u) + qadd8 r10, r11, r10 ; s = vp8_signed_char_clamp(ps1 + u) + eor r8, r8, lr ; *oq1 = s^0x80 + eor r10, r10, lr ; *op1 = s^0x80 + + ldrb r11, [src, #-5] ; load p2 for 1/7th difference across boundary + strb r10, [src, #-4] ; store op1 + strb r8, [src, #-1] ; store oq1 + ldrb r9, [src], pstep ; load q2 for 1/7th difference across boundary + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + orr r11, r11, r6, lsl #8 + orr r9, r9, r7, lsl #8 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + + mov r10, r10, lsr #8 + mov r8, r8, lsr #8 + orr r11, r11, r6, lsl #16 + orr r9, r9, r7, lsl #16 + + ldrb r6, [src, #-5] + strb r10, [src, #-4] + strb r8, [src, #-1] + ldrb r7, [src], pstep + orr r11, r11, r6, lsl #24 + orr r9, r9, r7, lsl #24 + + ;roughly 1/7th difference across boundary + eor r9, r9, lr + eor r11, r11, lr + + mov lr, #0x9 ; 9 + mov r7, #0x3f ; 63 + + sxtb16 r6, r12 + sxtb16 r10, r12, ror #8 + smlabb r8, r6, lr, r7 + smlatb r6, r6, lr, r7 + smlabb r12, r10, lr, r7 + smlatb r10, r10, lr, r7 + ssat r8, #8, r8, asr #7 + ssat r6, #8, r6, asr #7 + ssat r12, #8, r12, asr #7 + ssat r10, #8, r10, asr #7 + + sub src, src, pstep, lsl #2 + + pkhbt r6, r8, r6, lsl #16 + pkhbt r10, r12, r10, lsl #16 + + uxtb16 r6, r6 + uxtb16 r10, r10 + + ldr lr, c0x80808080 + + orr r10, r6, r10, lsl #8 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + + qadd8 r8, r11, r10 ; s = vp8_signed_char_clamp(ps2 + u) + qsub8 r10, r9, r10 ; s = vp8_signed_char_clamp(qs2 - u) + eor r8, r8, lr ; *op2 = s^0x80 + eor r10, r10, lr ; *oq2 = s^0x80 + + strb r8, [src, #-5] ; store *op2 + strb r10, [src], pstep ; store *oq2 + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + mov r8, r8, lsr #8 + mov r10, r10, lsr #8 + strb r8, [src, #-5] + strb r10, [src], pstep + + ;adjust src pointer for next loop + sub src, src, #2 + +|mbvskip_filter| + sub src, src, #4 + subs count, count, #1 + + ldrne r6, [src], pstep ; load source data + ldrne r7, [src], pstep + ldrne r8, [src], pstep + ldrne lr, [src], pstep + + bne MBVnext8 + + add sp, sp, #16 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_mbloop_filter_vertical_edge_armv6| + +; Constant Pool +c0x80808080 DCD 0x80808080 +c0x03030303 DCD 0x03030303 +c0x04040404 DCD 0x04040404 +c0x01010101 DCD 0x01010101 +c0x7F7F7F7F DCD 0x7F7F7F7F + + END
diff --git a/vp8/common/arm/armv6/recon_v6.asm b/vp8/common/arm/armv6/recon_v6.asm new file mode 100644 index 0000000..085ff80 --- /dev/null +++ b/vp8/common/arm/armv6/recon_v6.asm
@@ -0,0 +1,280 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_recon_b_armv6| + EXPORT |vp8_recon2b_armv6| + EXPORT |vp8_recon4b_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code +prd RN r0 +dif RN r1 +dst RN r2 +stride RN r3 + +;void recon_b(unsigned char *pred_ptr, short *diff_ptr, unsigned char *dst_ptr, int stride) +; R0 char* pred_ptr +; R1 short * dif_ptr +; R2 char * dst_ptr +; R3 int stride + +; Description: +; Loop through the block adding the Pred and Diff together. Clamp and then +; store back into the Dst. + +; Restrictions : +; all buffers are expected to be 4 byte aligned coming in and +; going out. +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +; +; +; +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_recon_b_armv6| PROC + stmdb sp!, {r4 - r9, lr} + + ;0, 1, 2, 3 + ldr r4, [prd], #16 ; 3 | 2 | 1 | 0 + ldr r6, [dif, #0] ; 1 | 0 + ldr r7, [dif, #4] ; 3 | 2 + + pkhbt r8, r6, r7, lsl #16 ; 2 | 0 + pkhtb r9, r7, r6, asr #16 ; 3 | 1 + + uxtab16 r8, r8, r4 ; 2 | 0 + 3 | 2 | 2 | 0 + uxtab16 r9, r9, r4, ror #8 ; 3 | 1 + 0 | 3 | 2 | 1 + + usat16 r8, #8, r8 + usat16 r9, #8, r9 + add dif, dif, #32 + orr r8, r8, r9, lsl #8 + + str r8, [dst], stride + + ;0, 1, 2, 3 + ldr r4, [prd], #16 ; 3 | 2 | 1 | 0 +;; ldr r6, [dif, #8] ; 1 | 0 +;; ldr r7, [dif, #12] ; 3 | 2 + ldr r6, [dif, #0] ; 1 | 0 + ldr r7, [dif, #4] ; 3 | 2 + + pkhbt r8, r6, r7, lsl #16 ; 2 | 0 + pkhtb r9, r7, r6, asr #16 ; 3 | 1 + + uxtab16 r8, r8, r4 ; 2 | 0 + 3 | 2 | 2 | 0 + uxtab16 r9, r9, r4, ror #8 ; 3 | 1 + 0 | 3 | 2 | 1 + + usat16 r8, #8, r8 + usat16 r9, #8, r9 + add dif, dif, #32 + orr r8, r8, r9, lsl #8 + + str r8, [dst], stride + + ;0, 1, 2, 3 + ldr r4, [prd], #16 ; 3 | 2 | 1 | 0 +;; ldr r6, [dif, #16] ; 1 | 0 +;; ldr r7, [dif, #20] ; 3 | 2 + ldr r6, [dif, #0] ; 1 | 0 + ldr r7, [dif, #4] ; 3 | 2 + + pkhbt r8, r6, r7, lsl #16 ; 2 | 0 + pkhtb r9, r7, r6, asr #16 ; 3 | 1 + + uxtab16 r8, r8, r4 ; 2 | 0 + 3 | 2 | 2 | 0 + uxtab16 r9, r9, r4, ror #8 ; 3 | 1 + 0 | 3 | 2 | 1 + + usat16 r8, #8, r8 + usat16 r9, #8, r9 + add dif, dif, #32 + orr r8, r8, r9, lsl #8 + + str r8, [dst], stride + + ;0, 1, 2, 3 + ldr r4, [prd], #16 ; 3 | 2 | 1 | 0 +;; ldr r6, [dif, #24] ; 1 | 0 +;; ldr r7, [dif, #28] ; 3 | 2 + ldr r6, [dif, #0] ; 1 | 0 + ldr r7, [dif, #4] ; 3 | 2 + + pkhbt r8, r6, r7, lsl #16 ; 2 | 0 + pkhtb r9, r7, r6, asr #16 ; 3 | 1 + + uxtab16 r8, r8, r4 ; 2 | 0 + 3 | 2 | 2 | 0 + uxtab16 r9, r9, r4, ror #8 ; 3 | 1 + 0 | 3 | 2 | 1 + + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst], stride + + ldmia sp!, {r4 - r9, pc} + + ENDP ; |recon_b| + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +; +; +; +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +; R0 char *pred_ptr +; R1 short *dif_ptr +; R2 char *dst_ptr +; R3 int stride +|vp8_recon4b_armv6| PROC + stmdb sp!, {r4 - r9, lr} + + mov lr, #4 + +recon4b_loop + ;0, 1, 2, 3 + ldr r4, [prd], #4 ; 3 | 2 | 1 | 0 + ldr r6, [dif, #0] ; 1 | 0 + ldr r7, [dif, #4] ; 3 | 2 + + pkhbt r8, r6, r7, lsl #16 ; 2 | 0 + pkhtb r9, r7, r6, asr #16 ; 3 | 1 + + uxtab16 r8, r8, r4 ; 2 | 0 + 3 | 2 | 2 | 0 + uxtab16 r9, r9, r4, ror #8 ; 3 | 1 + 0 | 3 | 2 | 1 + + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst] + + ;4, 5, 6, 7 + ldr r4, [prd], #4 +;; ldr r6, [dif, #32] +;; ldr r7, [dif, #36] + ldr r6, [dif, #8] + ldr r7, [dif, #12] + + pkhbt r8, r6, r7, lsl #16 + pkhtb r9, r7, r6, asr #16 + + uxtab16 r8, r8, r4 + uxtab16 r9, r9, r4, ror #8 + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst, #4] + + ;8, 9, 10, 11 + ldr r4, [prd], #4 +;; ldr r6, [dif, #64] +;; ldr r7, [dif, #68] + ldr r6, [dif, #16] + ldr r7, [dif, #20] + + pkhbt r8, r6, r7, lsl #16 + pkhtb r9, r7, r6, asr #16 + + uxtab16 r8, r8, r4 + uxtab16 r9, r9, r4, ror #8 + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst, #8] + + ;12, 13, 14, 15 + ldr r4, [prd], #4 +;; ldr r6, [dif, #96] +;; ldr r7, [dif, #100] + ldr r6, [dif, #24] + ldr r7, [dif, #28] + + pkhbt r8, r6, r7, lsl #16 + pkhtb r9, r7, r6, asr #16 + + uxtab16 r8, r8, r4 + uxtab16 r9, r9, r4, ror #8 + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst, #12] + + add dst, dst, stride +;; add dif, dif, #8 + add dif, dif, #32 + + subs lr, lr, #1 + bne recon4b_loop + + ldmia sp!, {r4 - r9, pc} + + ENDP ; |Recon4B| + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +; +; +; +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +; R0 char *pred_ptr +; R1 short *dif_ptr +; R2 char *dst_ptr +; R3 int stride +|vp8_recon2b_armv6| PROC + stmdb sp!, {r4 - r9, lr} + + mov lr, #4 + +recon2b_loop + ;0, 1, 2, 3 + ldr r4, [prd], #4 + ldr r6, [dif, #0] + ldr r7, [dif, #4] + + pkhbt r8, r6, r7, lsl #16 + pkhtb r9, r7, r6, asr #16 + + uxtab16 r8, r8, r4 + uxtab16 r9, r9, r4, ror #8 + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst] + + ;4, 5, 6, 7 + ldr r4, [prd], #4 +;; ldr r6, [dif, #32] +;; ldr r7, [dif, #36] + ldr r6, [dif, #8] + ldr r7, [dif, #12] + + pkhbt r8, r6, r7, lsl #16 + pkhtb r9, r7, r6, asr #16 + + uxtab16 r8, r8, r4 + uxtab16 r9, r9, r4, ror #8 + usat16 r8, #8, r8 + usat16 r9, #8, r9 + orr r8, r8, r9, lsl #8 + + str r8, [dst, #4] + + add dst, dst, stride +;; add dif, dif, #8 + add dif, dif, #16 + + subs lr, lr, #1 + bne recon2b_loop + + ldmia sp!, {r4 - r9, pc} + + ENDP ; |Recon2B| + + END
diff --git a/vp8/common/arm/armv6/simpleloopfilter_v6.asm b/vp8/common/arm/armv6/simpleloopfilter_v6.asm new file mode 100644 index 0000000..15c6c7d --- /dev/null +++ b/vp8/common/arm/armv6/simpleloopfilter_v6.asm
@@ -0,0 +1,321 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_simple_horizontal_edge_armv6| + EXPORT |vp8_loop_filter_simple_vertical_edge_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code + + MACRO + TRANSPOSE_MATRIX $a0, $a1, $a2, $a3, $b0, $b1, $b2, $b3 + ; input: $a0, $a1, $a2, $a3; output: $b0, $b1, $b2, $b3 + ; a0: 03 02 01 00 + ; a1: 13 12 11 10 + ; a2: 23 22 21 20 + ; a3: 33 32 31 30 + ; b3 b2 b1 b0 + + uxtb16 $b1, $a1 ; xx 12 xx 10 + uxtb16 $b0, $a0 ; xx 02 xx 00 + uxtb16 $b3, $a3 ; xx 32 xx 30 + uxtb16 $b2, $a2 ; xx 22 xx 20 + orr $b1, $b0, $b1, lsl #8 ; 12 02 10 00 + orr $b3, $b2, $b3, lsl #8 ; 32 22 30 20 + + uxtb16 $a1, $a1, ror #8 ; xx 13 xx 11 + uxtb16 $a3, $a3, ror #8 ; xx 33 xx 31 + uxtb16 $a0, $a0, ror #8 ; xx 03 xx 01 + uxtb16 $a2, $a2, ror #8 ; xx 23 xx 21 + orr $a0, $a0, $a1, lsl #8 ; 13 03 11 01 + orr $a2, $a2, $a3, lsl #8 ; 33 23 31 21 + + pkhtb $b2, $b3, $b1, asr #16 ; 32 22 12 02 -- p1 + pkhbt $b0, $b1, $b3, lsl #16 ; 30 20 10 00 -- p3 + + pkhtb $b3, $a2, $a0, asr #16 ; 33 23 13 03 -- p0 + pkhbt $b1, $a0, $a2, lsl #16 ; 31 21 11 01 -- p2 + MEND + + +src RN r0 +pstep RN r1 + +;r0 unsigned char *src_ptr, +;r1 int src_pixel_step, +;r2 const char *flimit, +;r3 const char *limit, +;stack const char *thresh, +;stack int count + +;Note: All 16 elements in flimit are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_simple_horizontal_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + sub src, src, pstep, lsl #1 ; move src pointer down by 2 lines + + ldr r12, [r3], #4 ; limit + ldr r3, [src], pstep ; p1 + + ldr r9, [sp, #36] ; count for 8-in-parallel + ldr r4, [src], pstep ; p0 + + ldr r7, [r2], #4 ; flimit + ldr r5, [src], pstep ; q0 + ldr r2, c0x80808080 + + ldr r6, [src] ; q1 + + uadd8 r7, r7, r7 ; flimit * 2 + mov r9, r9, lsl #1 ; 4-in-parallel + uadd8 r12, r7, r12 ; flimit * 2 + limit + +|simple_hnext8| + ; vp8_simple_filter_mask() function + + uqsub8 r7, r3, r6 ; p1 - q1 + uqsub8 r8, r6, r3 ; q1 - p1 + uqsub8 r10, r4, r5 ; p0 - q0 + uqsub8 r11, r5, r4 ; q0 - p0 + orr r8, r8, r7 ; abs(p1 - q1) + ldr lr, c0x7F7F7F7F ; 01111111 mask + orr r10, r10, r11 ; abs(p0 - q0) + and r8, lr, r8, lsr #1 ; abs(p1 - q1) / 2 + uqadd8 r10, r10, r10 ; abs(p0 - q0) * 2 + mvn lr, #0 ; r10 == -1 + uqadd8 r10, r10, r8 ; abs(p0 - q0)*2 + abs(p1 - q1)/2 + ; STALL waiting on r10 :( + uqsub8 r10, r10, r12 ; compare to flimit + mov r8, #0 + + usub8 r10, r8, r10 ; use usub8 instead of ssub8 + ; STALL (maybe?) when are flags set? :/ + sel r10, lr, r8 ; filter mask: lr + + cmp r10, #0 + beq simple_hskip_filter ; skip filtering + + ;vp8_simple_filter() function + + eor r3, r3, r2 ; p1 offset to convert to a signed value + eor r6, r6, r2 ; q1 offset to convert to a signed value + eor r4, r4, r2 ; p0 offset to convert to a signed value + eor r5, r5, r2 ; q0 offset to convert to a signed value + + qsub8 r3, r3, r6 ; vp8_filter (r3) = vp8_signed_char_clamp(p1-q1) + qsub8 r6, r5, r4 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( q0 - p0)) + + qadd8 r3, r3, r6 + ldr r8, c0x03030303 ; r8 = 3 + + qadd8 r3, r3, r6 + ldr r7, c0x04040404 + + qadd8 r3, r3, r6 + and r3, r3, lr ; vp8_filter &= mask; + + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r3 , r8 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r3 , r3 , r7 ; Filter1 (r3) = vp8_signed_char_clamp(vp8_filter+4) + + mov r7, #0 + shadd8 r8 , r8 , r7 ; Filter2 >>= 3 + shadd8 r3 , r3 , r7 ; Filter1 >>= 3 + shadd8 r8 , r8 , r7 + shadd8 r3 , r3 , r7 + shadd8 r8 , r8 , r7 ; r8: Filter2 + shadd8 r3 , r3 , r7 ; r7: filter1 + + ;calculate output + sub src, src, pstep, lsl #1 + + qadd8 r4, r4, r8 ; u = vp8_signed_char_clamp(p0 + Filter2) + qsub8 r5 ,r5, r3 ; u = vp8_signed_char_clamp(q0 - Filter1) + eor r4, r4, r2 ; *op0 = u^0x80 + str r4, [src], pstep ; store op0 result + eor r5, r5, r2 ; *oq0 = u^0x80 + str r5, [src], pstep ; store oq0 result + +|simple_hskip_filter| + add src, src, #4 + sub src, src, pstep + sub src, src, pstep, lsl #1 + + subs r9, r9, #1 + + ;pld [src] + ;pld [src, pstep] + ;pld [src, pstep, lsl #1] + + ldrne r3, [src], pstep ; p1 + ldrne r4, [src], pstep ; p0 + ldrne r5, [src], pstep ; q0 + ldrne r6, [src] ; q1 + + bne simple_hnext8 + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_loop_filter_simple_horizontal_edge_armv6| + + +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +|vp8_loop_filter_simple_vertical_edge_armv6| PROC +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + stmdb sp!, {r4 - r11, lr} + + ldr r12, [r2], #4 ; r12: flimit + ldr r2, c0x80808080 + ldr r7, [r3], #4 ; limit + + ; load soure data to r7, r8, r9, r10 + ldrh r3, [src, #-2] + ldrh r4, [src], pstep + uadd8 r12, r12, r12 ; flimit * 2 + + ldrh r5, [src, #-2] + ldrh r6, [src], pstep + uadd8 r12, r12, r7 ; flimit * 2 + limit + + pkhbt r7, r3, r4, lsl #16 + + ldrh r3, [src, #-2] + ldrh r4, [src], pstep + ldr r11, [sp, #40] ; count (r11) for 8-in-parallel + + pkhbt r8, r5, r6, lsl #16 + + ldrh r5, [src, #-2] + ldrh r6, [src], pstep + mov r11, r11, lsl #1 ; 4-in-parallel + +|simple_vnext8| + ; vp8_simple_filter_mask() function + pkhbt r9, r3, r4, lsl #16 + pkhbt r10, r5, r6, lsl #16 + + ;transpose r7, r8, r9, r10 to r3, r4, r5, r6 + TRANSPOSE_MATRIX r7, r8, r9, r10, r3, r4, r5, r6 + + uqsub8 r7, r3, r6 ; p1 - q1 + uqsub8 r8, r6, r3 ; q1 - p1 + uqsub8 r9, r4, r5 ; p0 - q0 + uqsub8 r10, r5, r4 ; q0 - p0 + orr r7, r7, r8 ; abs(p1 - q1) + orr r9, r9, r10 ; abs(p0 - q0) + ldr lr, c0x7F7F7F7F ; 0111 1111 mask + uqadd8 r9, r9, r9 ; abs(p0 - q0) * 2 + and r7, lr, r7, lsr #1 ; abs(p1 - q1) / 2 + mov r8, #0 + uqadd8 r7, r7, r9 ; abs(p0 - q0)*2 + abs(p1 - q1)/2 + mvn r10, #0 ; r10 == -1 + uqsub8 r7, r7, r12 ; compare to flimit + + usub8 r7, r8, r7 + sel r7, r10, r8 ; filter mask: lr + + cmp lr, #0 + beq simple_vskip_filter ; skip filtering + + ;vp8_simple_filter() function + eor r3, r3, r2 ; p1 offset to convert to a signed value + eor r6, r6, r2 ; q1 offset to convert to a signed value + eor r4, r4, r2 ; p0 offset to convert to a signed value + eor r5, r5, r2 ; q0 offset to convert to a signed value + + qsub8 r3, r3, r6 ; vp8_filter (r3) = vp8_signed_char_clamp(p1-q1) + qsub8 r6, r5, r4 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( q0 - p0)) + + qadd8 r3, r3, r6 + ldr r8, c0x03030303 ; r8 = 3 + + qadd8 r3, r3, r6 + ldr r7, c0x04040404 + + qadd8 r3, r3, r6 + and r3, r3, lr ; vp8_filter &= mask + + ;save bottom 3 bits so that we round one side +4 and the other +3 + qadd8 r8 , r3 , r8 ; Filter2 (r8) = vp8_signed_char_clamp(vp8_filter+3) + qadd8 r3 , r3 , r7 ; Filter1 (r3) = vp8_signed_char_clamp(vp8_filter+4) + + mov r7, #0 + shadd8 r8 , r8 , r7 ; Filter2 >>= 3 + shadd8 r3 , r3 , r7 ; Filter1 >>= 3 + shadd8 r8 , r8 , r7 + shadd8 r3 , r3 , r7 + shadd8 r8 , r8 , r7 ; r8: filter2 + shadd8 r3 , r3 , r7 ; r7: filter1 + + ;calculate output + sub src, src, pstep, lsl #2 + + qadd8 r4, r4, r8 ; u = vp8_signed_char_clamp(p0 + Filter2) + qsub8 r5, r5, r3 ; u = vp8_signed_char_clamp(q0 - Filter1) + eor r4, r4, r2 ; *op0 = u^0x80 + eor r5, r5, r2 ; *oq0 = u^0x80 + + strb r4, [src, #-1] ; store the result + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + mov r4, r4, lsr #8 + strb r5, [src], pstep + mov r5, r5, lsr #8 + + strb r4, [src, #-1] + strb r5, [src], pstep + +|simple_vskip_filter| + subs r11, r11, #1 + + ;pld [src] + ;pld [src, pstep] + ;pld [src, pstep, lsl #1] + + ; load soure data to r7, r8, r9, r10 + ldrneh r3, [src, #-2] + ldrneh r4, [src], pstep + + ldrneh r5, [src, #-2] + ldrneh r6, [src], pstep + + pkhbt r7, r3, r4, lsl #16 + + ldrneh r3, [src, #-2] + ldrneh r4, [src], pstep + + pkhbt r8, r5, r6, lsl #16 + + ldrneh r5, [src, #-2] + ldrneh r6, [src], pstep + + bne simple_vnext8 + + ldmia sp!, {r4 - r12, pc} + ENDP ; |vp8_loop_filter_simple_vertical_edge_armv6| + +; Constant Pool +c0x80808080 DCD 0x80808080 +c0x03030303 DCD 0x03030303 +c0x04040404 DCD 0x04040404 +c0x01010101 DCD 0x01010101 +c0x7F7F7F7F DCD 0x7F7F7F7F + + END
diff --git a/vp8/common/arm/armv6/sixtappredict8x4_v6.asm b/vp8/common/arm/armv6/sixtappredict8x4_v6.asm new file mode 100644 index 0000000..551d863 --- /dev/null +++ b/vp8/common/arm/armv6/sixtappredict8x4_v6.asm
@@ -0,0 +1,277 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x4_armv6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------------- +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack unsigned char *dst_ptr, +; stack int dst_pitch +;------------------------------------- +;note: In first pass, store the result in transpose(8linesx9columns) on stack. Temporary stack size is 184. +;Line width is 20 that is 9 short data plus 2 to make it 4bytes aligned. In second pass, load data from stack, +;and the result is stored in transpose. +|vp8_sixtap_predict8x4_armv6| PROC + stmdb sp!, {r4 - r11, lr} + sub sp, sp, #184 ;reserve space on stack for temporary storage: 20x(8+1) +4 + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + str r3, [sp], #4 ;store yoffset + beq skip_firstpass_filter + +;first-pass filter + ldr r12, _filter8_coeff_ + sub r0, r0, r1, lsl #1 + + add r2, r12, r2, lsl #4 ;calculate filter location + add r0, r0, #3 ;adjust src only for loading convinience + + ldr r3, [r2] ; load up packed filter coefficients + ldr r4, [r2, #4] + ldr r5, [r2, #8] + + mov r2, #0x90000 ; height=9 is top part of counter + + sub r1, r1, #8 + mov lr, #20 + +|first_pass_hloop_v6| + ldrb r6, [r0, #-5] ; load source data + ldrb r7, [r0, #-4] + ldrb r8, [r0, #-3] + ldrb r9, [r0, #-2] + ldrb r10, [r0, #-1] + + orr r2, r2, #0x4 ; construct loop counter. width=8=4x2 + + pkhbt r6, r6, r7, lsl #16 ; r7 | r6 + pkhbt r7, r7, r8, lsl #16 ; r8 | r7 + + pkhbt r8, r8, r9, lsl #16 ; r9 | r8 + pkhbt r9, r9, r10, lsl #16 ; r10 | r9 + +|first_pass_wloop_v6| + smuad r11, r6, r3 ; vp8_filter[0], vp8_filter[1] + smuad r12, r7, r3 + + ldrb r6, [r0], #1 + + smlad r11, r8, r4, r11 ; vp8_filter[2], vp8_filter[3] + ldrb r7, [r0], #1 + smlad r12, r9, r4, r12 + + pkhbt r10, r10, r6, lsl #16 ; r10 | r9 + pkhbt r6, r6, r7, lsl #16 ; r11 | r10 + smlad r11, r10, r5, r11 ; vp8_filter[4], vp8_filter[5] + smlad r12, r6, r5, r12 + + sub r2, r2, #1 + + add r11, r11, #0x40 ; round_shift_and_clamp + tst r2, #0xff ; test loop counter + usat r11, #8, r11, asr #7 + add r12, r12, #0x40 + strh r11, [sp], lr ; result is transposed and stored, which + usat r12, #8, r12, asr #7 + + strh r12, [sp], lr + + movne r11, r6 + movne r12, r7 + + movne r6, r8 + movne r7, r9 + movne r8, r10 + movne r9, r11 + movne r10, r12 + + bne first_pass_wloop_v6 + + ;;add r9, ppl, #30 ; attempt to load 2 adjacent cache lines + ;;IF ARCHITECTURE=6 + ;pld [src, ppl] + ;;pld [src, r9] + ;;ENDIF + + subs r2, r2, #0x10000 + + mov r6, #158 + sub sp, sp, r6 + + add r0, r0, r1 ; move to next input line + + bne first_pass_hloop_v6 + +;second pass filter +secondpass_filter + mov r1, #18 + sub sp, sp, r1 ; 18+4 + + ldr r3, [sp, #-4] ; load back yoffset + ldr r0, [sp, #216] ; load dst address from stack 180+36 + ldr r1, [sp, #220] ; load dst stride from stack 180+40 + + cmp r3, #0 + beq skip_secondpass_filter + + ldr r12, _filter8_coeff_ + add lr, r12, r3, lsl #4 ;calculate filter location + + mov r2, #0x00080000 + + ldr r3, [lr] ; load up packed filter coefficients + ldr r4, [lr, #4] + ldr r5, [lr, #8] + + pkhbt r12, r4, r3 ; pack the filter differently + pkhbt r11, r5, r4 + +second_pass_hloop_v6 + ldr r6, [sp] ; load the data + ldr r7, [sp, #4] + + orr r2, r2, #2 ; loop counter + +second_pass_wloop_v6 + smuad lr, r3, r6 ; apply filter + smulbt r10, r3, r6 + + ldr r8, [sp, #8] + + smlad lr, r4, r7, lr + smladx r10, r12, r7, r10 + + ldrh r9, [sp, #12] + + smlad lr, r5, r8, lr + smladx r10, r11, r8, r10 + + add sp, sp, #4 + smlatb r10, r5, r9, r10 + + sub r2, r2, #1 + + add lr, lr, #0x40 ; round_shift_and_clamp + tst r2, #0xff + usat lr, #8, lr, asr #7 + add r10, r10, #0x40 + strb lr, [r0], r1 ; the result is transposed back and stored + usat r10, #8, r10, asr #7 + + strb r10, [r0],r1 + + movne r6, r7 + movne r7, r8 + + bne second_pass_wloop_v6 + + subs r2, r2, #0x10000 + add sp, sp, #12 ; updata src for next loop (20-8) + sub r0, r0, r1, lsl #2 + add r0, r0, #1 + + bne second_pass_hloop_v6 + + add sp, sp, #20 + ldmia sp!, {r4 - r11, pc} + +;-------------------- +skip_firstpass_filter + sub r0, r0, r1, lsl #1 + sub r1, r1, #8 + mov r2, #9 + mov r3, #20 + +skip_firstpass_hloop + ldrb r4, [r0], #1 ; load data + subs r2, r2, #1 + ldrb r5, [r0], #1 + strh r4, [sp], r3 ; store it to immediate buffer + ldrb r6, [r0], #1 ; load data + strh r5, [sp], r3 + ldrb r7, [r0], #1 + strh r6, [sp], r3 + ldrb r8, [r0], #1 + strh r7, [sp], r3 + ldrb r9, [r0], #1 + strh r8, [sp], r3 + ldrb r10, [r0], #1 + strh r9, [sp], r3 + ldrb r11, [r0], #1 + strh r10, [sp], r3 + add r0, r0, r1 ; move to next input line + strh r11, [sp], r3 + + mov r4, #158 + sub sp, sp, r4 ; move over to next column + bne skip_firstpass_hloop + + b secondpass_filter + +;-------------------- +skip_secondpass_filter + mov r2, #8 + add sp, sp, #4 ;start from src[0] instead of src[-2] + +skip_secondpass_hloop + ldr r6, [sp], #4 + subs r2, r2, #1 + ldr r8, [sp], #4 + + mov r7, r6, lsr #16 ; unpack + strb r6, [r0], r1 + mov r9, r8, lsr #16 + strb r7, [r0], r1 + add sp, sp, #12 ; 20-8 + strb r8, [r0], r1 + strb r9, [r0], r1 + + sub r0, r0, r1, lsl #2 + add r0, r0, #1 + + bne skip_secondpass_hloop + + add sp, sp, #16 ; 180 - (160 +4) + + ldmia sp!, {r4 - r11, pc} + + ENDP + +;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_filter8_coeff_ + DCD filter8_coeff +filter8_coeff + DCD 0x00000000, 0x00000080, 0x00000000, 0x00000000 + DCD 0xfffa0000, 0x000c007b, 0x0000ffff, 0x00000000 + DCD 0xfff50002, 0x0024006c, 0x0001fff8, 0x00000000 + DCD 0xfff70000, 0x0032005d, 0x0000fffa, 0x00000000 + DCD 0xfff00003, 0x004d004d, 0x0003fff0, 0x00000000 + DCD 0xfffa0000, 0x005d0032, 0x0000fff7, 0x00000000 + DCD 0xfff80001, 0x006c0024, 0x0002fff5, 0x00000000 + DCD 0xffff0000, 0x007b000c, 0x0000fffa, 0x00000000 + + ;DCD 0, 0, 128, 0, 0, 0 + ;DCD 0, -6, 123, 12, -1, 0 + ;DCD 2, -11, 108, 36, -8, 1 + ;DCD 0, -9, 93, 50, -6, 0 + ;DCD 3, -16, 77, 77, -16, 3 + ;DCD 0, -6, 50, 93, -9, 0 + ;DCD 1, -8, 36, 108, -11, 2 + ;DCD 0, -1, 12, 123, -6, 0 + + END
diff --git a/vp8/common/arm/bilinearfilter_arm.c b/vp8/common/arm/bilinearfilter_arm.c new file mode 100644 index 0000000..bf972a3 --- /dev/null +++ b/vp8/common/arm/bilinearfilter_arm.c
@@ -0,0 +1,211 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> +#include "subpixel.h" + +#define BLOCK_HEIGHT_WIDTH 4 +#define VP8_FILTER_WEIGHT 128 +#define VP8_FILTER_SHIFT 7 + +static const short bilinear_filters[8][2] = +{ + { 128, 0 }, + { 112, 16 }, + { 96, 32 }, + { 80, 48 }, + { 64, 64 }, + { 48, 80 }, + { 32, 96 }, + { 16, 112 } +}; + + +extern void vp8_filter_block2d_bil_first_pass_armv6 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); + +extern void vp8_filter_block2d_bil_second_pass_armv6 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); + +/* +void vp8_filter_block2d_bil_first_pass_6 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + + for ( i=0; i<output_height; i++ ) + { + for ( j=0; j<output_width; j++ ) + { + // Apply bilinear filter + output_ptr[j] = ( ( (int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[1] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT/2) ) >> VP8_FILTER_SHIFT; + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +void vp8_filter_block2d_bil_second_pass_6 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i,j; + int Temp; + + for ( i=0; i<output_height; i++ ) + { + for ( j=0; j<output_width; j++ ) + { + // Apply filter + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[output_width] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT/2); + output_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); + src_ptr++; + } + + // Next row... + //src_ptr += src_pixels_per_line - output_width; + output_ptr += output_pitch; + } +} +*/ + +void vp8_filter_block2d_bil_armv6 +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int dst_pitch, + const short *HFilter, + const short *VFilter, + int Width, + int Height +) +{ + + unsigned short FData[36*16]; // Temp data bufffer used in filtering + + // First filter 1-D horizontally... + // pixel_step = 1; + vp8_filter_block2d_bil_first_pass_armv6(src_ptr, FData, src_pixels_per_line, Height + 1, Width, HFilter); + + // then 1-D vertically... + vp8_filter_block2d_bil_second_pass_armv6(FData, output_ptr, dst_pitch, Height, Width, VFilter); +} + + +void vp8_bilinear_predict4x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 4, 4); +} + +void vp8_bilinear_predict8x8_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 8); +} + +void vp8_bilinear_predict8x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 4); +} + +void vp8_bilinear_predict16x16_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil_armv6(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 16, 16); +}
diff --git a/vp8/common/arm/filter_arm.c b/vp8/common/arm/filter_arm.c new file mode 100644 index 0000000..2a4640c --- /dev/null +++ b/vp8/common/arm/filter_arm.c
@@ -0,0 +1,234 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include <math.h> +#include "subpixel.h" +#include "vpx_ports/mem.h" + +#define BLOCK_HEIGHT_WIDTH 4 +#define VP8_FILTER_WEIGHT 128 +#define VP8_FILTER_SHIFT 7 + +DECLARE_ALIGNED(16, static const short, sub_pel_filters[8][6]) = +{ + { 0, 0, 128, 0, 0, 0 }, // note that 1/8 pel positions are just as per alpha -0.5 bicubic + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, // New 1/4 pel 6 tap filter + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, // New 1/2 pel 6 tap filter + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, // New 1/4 pel 6 tap filter + { 0, -1, 12, 123, -6, 0 }, +}; + + +extern void vp8_filter_block2d_first_pass_armv6 +( + unsigned char *src_ptr, + short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_width, + unsigned int output_height, + const short *vp8_filter +); + +extern void vp8_filter_block2d_second_pass_armv6 +( + short *src_ptr, + unsigned char *output_ptr, + unsigned int output_pitch, + unsigned int cnt, + const short *vp8_filter +); + +extern void vp8_filter_block2d_first_pass_only_armv6 +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int cnt, + unsigned int output_pitch, + const short *vp8_filter +); + + +extern void vp8_filter_block2d_second_pass_only_armv6 +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int cnt, + unsigned int output_pitch, + const short *vp8_filter +); + +#if HAVE_ARMV6 +void vp8_sixtap_predict_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 12*4); // Temp data bufffer used in filtering + + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + // Vfilter is null. First pass only + if (xoffset && !yoffset) + { + //vp8_filter_block2d_first_pass_armv6 ( src_ptr, FData+2, src_pixels_per_line, 4, 4, HFilter ); + //vp8_filter_block2d_second_pass_armv6 ( FData+2, dst_ptr, dst_pitch, 4, VFilter ); + + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 4, dst_pitch, HFilter); + } + // Hfilter is null. Second pass only + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 4, dst_pitch, VFilter); + } + else + { + // Vfilter is a 4 tap filter + if (yoffset & 0x1) + vp8_filter_block2d_first_pass_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 4, 7, HFilter); + // Vfilter is 6 tap filter + else + vp8_filter_block2d_first_pass_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 4, 9, HFilter); + + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 4, VFilter); + } +} + +/* +void vp8_sixtap_predict8x4_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 16*8); // Temp data bufffer used in filtering + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + +// if (xoffset && !yoffset) +// { +// vp8_filter_block2d_first_pass_only_armv6 ( src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, HFilter ); +// } + // Hfilter is null. Second pass only +// else if (!xoffset && yoffset) +// { +// vp8_filter_block2d_second_pass_only_armv6 ( src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, VFilter ); +// } +// else +// { +// if (yoffset & 0x1) + // vp8_filter_block2d_first_pass_armv6 ( src_ptr-src_pixels_per_line, FData+1, src_pixels_per_line, 8, 7, HFilter ); + // else + + vp8_filter_block2d_first_pass_armv6 ( src_ptr-(2*src_pixels_per_line), FData, src_pixels_per_line, 8, 9, HFilter ); + + vp8_filter_block2d_second_pass_armv6 ( FData+2, dst_ptr, dst_pitch, 4, 8, VFilter ); +// } +} +*/ + +void vp8_sixtap_predict8x8_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 16*8); // Temp data bufffer used in filtering + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + if (xoffset && !yoffset) + { + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, HFilter); + } + // Hfilter is null. Second pass only + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 8, dst_pitch, VFilter); + } + else + { + if (yoffset & 0x1) + vp8_filter_block2d_first_pass_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 8, 11, HFilter); + else + vp8_filter_block2d_first_pass_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 8, 13, HFilter); + + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 8, VFilter); + } +} + + +void vp8_sixtap_predict16x16_armv6 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + DECLARE_ALIGNED_ARRAY(4, short, FData, 24*16); // Temp data bufffer used in filtering + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + if (xoffset && !yoffset) + { + vp8_filter_block2d_first_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 16, dst_pitch, HFilter); + } + // Hfilter is null. Second pass only + else if (!xoffset && yoffset) + { + vp8_filter_block2d_second_pass_only_armv6(src_ptr, dst_ptr, src_pixels_per_line, 16, dst_pitch, VFilter); + } + else + { + if (yoffset & 0x1) + vp8_filter_block2d_first_pass_armv6(src_ptr - src_pixels_per_line, FData + 1, src_pixels_per_line, 16, 19, HFilter); + else + vp8_filter_block2d_first_pass_armv6(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 16, 21, HFilter); + + vp8_filter_block2d_second_pass_armv6(FData + 2, dst_ptr, dst_pitch, 16, VFilter); + } + +} +#endif
diff --git a/vp8/common/arm/idct_arm.h b/vp8/common/arm/idct_arm.h new file mode 100644 index 0000000..f9ed21e --- /dev/null +++ b/vp8/common/arm/idct_arm.h
@@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef IDCT_ARM_H +#define IDCT_ARM_H + +#if HAVE_ARMV6 +extern prototype_idct(vp8_short_idct4x4llm_1_v6); +extern prototype_idct(vp8_short_idct4x4llm_v6_dual); +extern prototype_idct_scalar(vp8_dc_only_idct_armv6); +extern prototype_second_order(vp8_short_inv_walsh4x4_1_armv6); +extern prototype_second_order(vp8_short_inv_walsh4x4_armv6); + +#undef vp8_idct_idct1 +#define vp8_idct_idct1 vp8_short_idct4x4llm_1_v6 + +#undef vp8_idct_idct16 +#define vp8_idct_idct16 vp8_short_idct4x4llm_v6_dual + +#undef vp8_idct_idct1_scalar +#define vp8_idct_idct1_scalar vp8_dc_only_idct_armv6 + +#undef vp8_idct_iwalsh1 +#define vp8_idct_iwalsh1 vp8_short_inv_walsh4x4_1_armv6 + +#undef vp8_idct_iwalsh16 +#define vp8_idct_iwalsh16 vp8_short_inv_walsh4x4_armv6 +#endif + +#if HAVE_ARMV7 +extern prototype_idct(vp8_short_idct4x4llm_1_neon); +extern prototype_idct(vp8_short_idct4x4llm_neon); +extern prototype_idct_scalar(vp8_dc_only_idct_neon); +extern prototype_second_order(vp8_short_inv_walsh4x4_1_neon); +extern prototype_second_order(vp8_short_inv_walsh4x4_neon); + +#undef vp8_idct_idct1 +#define vp8_idct_idct1 vp8_short_idct4x4llm_1_neon + +#undef vp8_idct_idct16 +#define vp8_idct_idct16 vp8_short_idct4x4llm_neon + +#undef vp8_idct_idct1_scalar +#define vp8_idct_idct1_scalar vp8_dc_only_idct_neon + +#undef vp8_idct_iwalsh1 +#define vp8_idct_iwalsh1 vp8_short_inv_walsh4x4_1_neon + +#undef vp8_idct_iwalsh16 +#define vp8_idct_iwalsh16 vp8_short_inv_walsh4x4_neon +#endif + +#endif
diff --git a/vp8/common/arm/loopfilter_arm.c b/vp8/common/arm/loopfilter_arm.c new file mode 100644 index 0000000..fa7c626 --- /dev/null +++ b/vp8/common/arm/loopfilter_arm.c
@@ -0,0 +1,246 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include <math.h> +#include "loopfilter.h" +#include "onyxc_int.h" + +typedef void loop_filter_uvfunction +( + unsigned char *u, // source pointer + int p, // pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + unsigned char *v +); + +extern prototype_loopfilter(vp8_loop_filter_horizontal_edge_armv6); +extern prototype_loopfilter(vp8_loop_filter_vertical_edge_armv6); +extern prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_armv6); +extern prototype_loopfilter(vp8_mbloop_filter_vertical_edge_armv6); +extern prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_armv6); +extern prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_armv6); + +extern prototype_loopfilter(vp8_loop_filter_horizontal_edge_y_neon); +extern prototype_loopfilter(vp8_loop_filter_vertical_edge_y_neon); +extern prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_y_neon); +extern prototype_loopfilter(vp8_mbloop_filter_vertical_edge_y_neon); +extern prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_neon); +extern prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_neon); + +extern loop_filter_uvfunction vp8_loop_filter_horizontal_edge_uv_neon; +extern loop_filter_uvfunction vp8_loop_filter_vertical_edge_uv_neon; +extern loop_filter_uvfunction vp8_mbloop_filter_horizontal_edge_uv_neon; +extern loop_filter_uvfunction vp8_mbloop_filter_vertical_edge_uv_neon; + + +#if HAVE_ARMV6 +//ARMV6 loopfilter functions +// Horizontal MB filtering +void vp8_loop_filter_mbh_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_horizontal_edge_armv6(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_armv6(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_armv6(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + +void vp8_loop_filter_mbhs_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Vertical MB Filtering +void vp8_loop_filter_mbv_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_vertical_edge_armv6(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_armv6(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_armv6(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + +void vp8_loop_filter_mbvs_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Horizontal B Filtering +void vp8_loop_filter_bh_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_armv6(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_armv6(u_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_armv6(v_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + +void vp8_loop_filter_bhs_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_armv6(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + +// Vertical B Filtering +void vp8_loop_filter_bv_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_vertical_edge_armv6(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_armv6(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_armv6(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_armv6(u_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_armv6(v_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + +void vp8_loop_filter_bvs_armv6(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_armv6(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} +#endif + +#if HAVE_ARMV7 +// NEON loopfilter functions +// Horizontal MB filtering +void vp8_loop_filter_mbh_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_horizontal_edge_y_neon(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_uv_neon(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, v_ptr); +} + +void vp8_loop_filter_mbhs_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_neon(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Vertical MB Filtering +void vp8_loop_filter_mbv_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_vertical_edge_y_neon(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_uv_neon(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, v_ptr); +} + +void vp8_loop_filter_mbvs_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_neon(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Horizontal B Filtering +void vp8_loop_filter_bh_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_y_neon(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_uv_neon(u_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, v_ptr + 4 * uv_stride); +} + +void vp8_loop_filter_bhs_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_neon(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_neon(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_neon(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + +// Vertical B Filtering +void vp8_loop_filter_bv_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_y_neon(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_uv_neon(u_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, v_ptr + 4); +} + +void vp8_loop_filter_bvs_neon(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_neon(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_neon(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_neon(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} +#endif
diff --git a/vp8/common/arm/loopfilter_arm.h b/vp8/common/arm/loopfilter_arm.h new file mode 100644 index 0000000..4bb4945 --- /dev/null +++ b/vp8/common/arm/loopfilter_arm.h
@@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef LOOPFILTER_ARM_H +#define LOOPFILTER_ARM_H + +#if HAVE_ARMV6 +extern prototype_loopfilter_block(vp8_loop_filter_mbv_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_bv_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_mbh_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_bh_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_mbvs_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_bvs_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_mbhs_armv6); +extern prototype_loopfilter_block(vp8_loop_filter_bhs_armv6); + +#undef vp8_lf_normal_mb_v +#define vp8_lf_normal_mb_v vp8_loop_filter_mbv_armv6 + +#undef vp8_lf_normal_b_v +#define vp8_lf_normal_b_v vp8_loop_filter_bv_armv6 + +#undef vp8_lf_normal_mb_h +#define vp8_lf_normal_mb_h vp8_loop_filter_mbh_armv6 + +#undef vp8_lf_normal_b_h +#define vp8_lf_normal_b_h vp8_loop_filter_bh_armv6 + +#undef vp8_lf_simple_mb_v +#define vp8_lf_simple_mb_v vp8_loop_filter_mbvs_armv6 + +#undef vp8_lf_simple_b_v +#define vp8_lf_simple_b_v vp8_loop_filter_bvs_armv6 + +#undef vp8_lf_simple_mb_h +#define vp8_lf_simple_mb_h vp8_loop_filter_mbhs_armv6 + +#undef vp8_lf_simple_b_h +#define vp8_lf_simple_b_h vp8_loop_filter_bhs_armv6 +#endif + +#if HAVE_ARMV7 +extern prototype_loopfilter_block(vp8_loop_filter_mbv_neon); +extern prototype_loopfilter_block(vp8_loop_filter_bv_neon); +extern prototype_loopfilter_block(vp8_loop_filter_mbh_neon); +extern prototype_loopfilter_block(vp8_loop_filter_bh_neon); +extern prototype_loopfilter_block(vp8_loop_filter_mbvs_neon); +extern prototype_loopfilter_block(vp8_loop_filter_bvs_neon); +extern prototype_loopfilter_block(vp8_loop_filter_mbhs_neon); +extern prototype_loopfilter_block(vp8_loop_filter_bhs_neon); + +#undef vp8_lf_normal_mb_v +#define vp8_lf_normal_mb_v vp8_loop_filter_mbv_neon + +#undef vp8_lf_normal_b_v +#define vp8_lf_normal_b_v vp8_loop_filter_bv_neon + +#undef vp8_lf_normal_mb_h +#define vp8_lf_normal_mb_h vp8_loop_filter_mbh_neon + +#undef vp8_lf_normal_b_h +#define vp8_lf_normal_b_h vp8_loop_filter_bh_neon + +#undef vp8_lf_simple_mb_v +#define vp8_lf_simple_mb_v vp8_loop_filter_mbvs_neon + +#undef vp8_lf_simple_b_v +#define vp8_lf_simple_b_v vp8_loop_filter_bvs_neon + +#undef vp8_lf_simple_mb_h +#define vp8_lf_simple_mb_h vp8_loop_filter_mbhs_neon + +#undef vp8_lf_simple_b_h +#define vp8_lf_simple_b_h vp8_loop_filter_bhs_neon +#endif + +#endif
diff --git a/vp8/common/arm/neon/bilinearpredict16x16_neon.asm b/vp8/common/arm/neon/bilinearpredict16x16_neon.asm new file mode 100644 index 0000000..a2fea2b --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict16x16_neon.asm
@@ -0,0 +1,361 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict16x16_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_bilinear_predict16x16_neon| PROC + push {r4-r5, lr} + + ldr r12, _bifilter16_coeff_ + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16_only + + add r2, r12, r2, lsl #3 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {d31}, [r2] ;load first_pass filter + + beq firstpass_bfilter16x16_only + + sub sp, sp, #272 ;reserve space on stack for temporary storage + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + mov lr, sp + vld1.u8 {d5, d6, d7}, [r0], r1 + + mov r2, #3 ;loop counter + vld1.u8 {d8, d9, d10}, [r0], r1 + + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {d11, d12, d13}, [r0], r1 + + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (17x16) +filt_blk2d_fp16x16_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vqrshrn.u16 d21, q14, #7 + vld1.u8 {d5, d6, d7}, [r0], r1 + + vst1.u8 {d14, d15, d16, d17}, [lr]! ;store result + vld1.u8 {d8, d9, d10}, [r0], r1 + vst1.u8 {d18, d19, d20, d21}, [lr]! + vld1.u8 {d11, d12, d13}, [r0], r1 + + bne filt_blk2d_fp16x16_loop_neon + +;First-pass filtering for rest 5 lines + vld1.u8 {d14, d15, d16}, [r0], r1 + + vmull.u8 q9, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q10, d3, d0 + vmull.u8 q11, d5, d0 + vmull.u8 q12, d6, d0 + vmull.u8 q13, d8, d0 + vmull.u8 q14, d9, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + + vmlal.u8 q9, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q11, d5, d1 + vmlal.u8 q13, d8, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + + vmlal.u8 q10, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q12, d6, d1 + vmlal.u8 q14, d9, d1 + + vmull.u8 q1, d11, d0 + vmull.u8 q2, d12, d0 + vmull.u8 q3, d14, d0 + vmull.u8 q4, d15, d0 + + vext.8 d11, d11, d12, #1 ;construct src_ptr[1] + vext.8 d14, d14, d15, #1 + + vmlal.u8 q1, d11, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q3, d14, d1 + + vext.8 d12, d12, d13, #1 + vext.8 d15, d15, d16, #1 + + vmlal.u8 q2, d12, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q4, d15, d1 + + vqrshrn.u16 d10, q9, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d11, q10, #7 + vqrshrn.u16 d12, q11, #7 + vqrshrn.u16 d13, q12, #7 + vqrshrn.u16 d14, q13, #7 + vqrshrn.u16 d15, q14, #7 + vqrshrn.u16 d16, q1, #7 + vqrshrn.u16 d17, q2, #7 + vqrshrn.u16 d18, q3, #7 + vqrshrn.u16 d19, q4, #7 + + vst1.u8 {d10, d11, d12, d13}, [lr]! ;store result + vst1.u8 {d14, d15, d16, d17}, [lr]! + vst1.u8 {d18, d19}, [lr]! + +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + sub lr, lr, #272 + + vld1.u32 {d31}, [r3] ;load second_pass filter + + vld1.u8 {d22, d23}, [lr]! ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + mov r12, #4 ;loop counter + +filt_blk2d_sp16x16_loop_neon + vld1.u8 {d24, d25}, [lr]! + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {d26, d27}, [lr]! + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [lr]! + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [lr]! + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + subs r12, r12, #1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r4], r5 ;store result + vst1.u8 {d4, d5}, [r4], r5 + vst1.u8 {d6, d7}, [r4], r5 + vmov q11, q15 + vst1.u8 {d8, d9}, [r4], r5 + + bne filt_blk2d_sp16x16_loop_neon + + add sp, sp, #272 + + pop {r4-r5,pc} + +;-------------------- +firstpass_bfilter16x16_only + mov r2, #4 ;loop counter + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (16x16) +filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vld1.u8 {d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10}, [r0], r1 + vld1.u8 {d11, d12, d13}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * vp8_filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + vst1.u8 {d14, d15}, [r4], r5 ;store result + vqrshrn.u16 d21, q14, #7 + + vst1.u8 {d16, d17}, [r4], r5 + vst1.u8 {d18, d19}, [r4], r5 + vst1.u8 {d20, d21}, [r4], r5 + + bne filt_blk2d_fpo16x16_loop_neon + pop {r4-r5,pc} + +;--------------------- +secondpass_bfilter16x16_only +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + mov r12, #4 ;loop counter + vld1.u32 {d31}, [r3] ;load second_pass filter + vld1.u8 {d22, d23}, [r0], r1 ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + +filt_blk2d_spo16x16_loop_neon + vld1.u8 {d24, d25}, [r0], r1 + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {d26, d27}, [r0], r1 + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [r0], r1 + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [r0], r1 + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r4], r5 ;store result + subs r12, r12, #1 + vst1.u8 {d4, d5}, [r4], r5 + vmov q11, q15 + vst1.u8 {d6, d7}, [r4], r5 + vst1.u8 {d8, d9}, [r4], r5 + + bne filt_blk2d_spo16x16_loop_neon + pop {r4-r5,pc} + + ENDP + +;----------------- + AREA bifilters16_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_bifilter16_coeff_ + DCD bifilter16_coeff +bifilter16_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/common/arm/neon/bilinearpredict4x4_neon.asm b/vp8/common/arm/neon/bilinearpredict4x4_neon.asm new file mode 100644 index 0000000..74d2db5 --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict4x4_neon.asm
@@ -0,0 +1,134 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict4x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict4x4_neon| PROC + push {r4, lr} + + ldr r12, _bifilter4_coeff_ + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (5x4) + vld1.u8 {d2}, [r0], r1 ;load src data + add r2, r12, r2, lsl #3 ;calculate Hfilter location (2coeffsx4bytes=8bytes) + + vld1.u8 {d3}, [r0], r1 + vld1.u32 {d31}, [r2] ;first_pass filter + + vld1.u8 {d4}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0-d1) + vld1.u8 {d5}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {d6}, [r0], r1 + + vshr.u64 q4, q1, #8 ;construct src_ptr[1] + vshr.u64 q5, q2, #8 + vshr.u64 d12, d6, #8 + + vzip.32 d2, d3 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d4, d5 + vzip.32 d8, d9 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q8, d4, d0 + vmull.u8 q9, d6, d0 + + vmlal.u8 q7, d8, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q8, d10, d1 + vmlal.u8 q9, d12, d1 + + vqrshrn.u16 d28, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d29, q8, #7 + vqrshrn.u16 d30, q9, #7 + +;Second pass: 4x4 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 ;calculate Vfilter location + vld1.u32 {d31}, [r3] ;load second_pass filter + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d31[4] + + vmull.u8 q1, d28, d0 + vmull.u8 q2, d29, d0 + + vext.8 d26, d28, d29, #4 ;construct src_ptr[pixel_step] + vext.8 d27, d29, d30, #4 + + vmlal.u8 q1, d26, d1 + vmlal.u8 q2, d27, d1 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + + vst1.32 {d2[0]}, [r4] ;store result + vst1.32 {d2[1]}, [r0] + vst1.32 {d3[0]}, [r1] + vst1.32 {d3[1]}, [r2] + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + + vld1.32 {d28[0]}, [r0], r1 ;load src data + vld1.32 {d28[1]}, [r0], r1 + vld1.32 {d29[0]}, [r0], r1 + vld1.32 {d29[1]}, [r0], r1 + vld1.32 {d30[0]}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.32 {d28[0]}, [r4], lr ;store result + vst1.32 {d28[1]}, [r4], lr + vst1.32 {d29[0]}, [r4], lr + vst1.32 {d29[1]}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + AREA bilinearfilters4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_bifilter4_coeff_ + DCD bifilter4_coeff +bifilter4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/common/arm/neon/bilinearpredict8x4_neon.asm b/vp8/common/arm/neon/bilinearpredict8x4_neon.asm new file mode 100644 index 0000000..46ebb0e --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict8x4_neon.asm
@@ -0,0 +1,139 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict8x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict8x4_neon| PROC + push {r4, lr} + + ldr r12, _bifilter8x4_coeff_ + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (5x8) + add r2, r12, r2, lsl #3 ;calculate filter location + + vld1.u8 {q1}, [r0], r1 ;load src data + vld1.u32 {d31}, [r2] ;load first_pass filter + vld1.u8 {q2}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {q3}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {q4}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vld1.u8 {q5}, [r0], r1 + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + vmlal.u8 q10, d11, d1 + + vqrshrn.u16 d22, q6, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d23, q7, #7 + vqrshrn.u16 d24, q8, #7 + vqrshrn.u16 d25, q9, #7 + vqrshrn.u16 d26, q10, #7 + +;Second pass: 4x8 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 + add r0, r4, lr + + vld1.u32 {d31}, [r3] ;load second_pass filter + add r1, r0, lr + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q2, d23, d0 + vmull.u8 q3, d24, d0 + vmull.u8 q4, d25, d0 + + vmlal.u8 q1, d23, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d24, d1 + vmlal.u8 q3, d25, d1 + vmlal.u8 q4, d26, d1 + + add r2, r1, lr + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + + vst1.u8 {d2}, [r4] ;store result + vst1.u8 {d3}, [r0] + vst1.u8 {d4}, [r1] + vst1.u8 {d5}, [r2] + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + vld1.u8 {d22}, [r0], r1 ;load src data + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.u8 {d22}, [r4], lr ;store result + vst1.u8 {d23}, [r4], lr + vst1.u8 {d24}, [r4], lr + vst1.u8 {d25}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + AREA bifilters8x4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_bifilter8x4_coeff_ + DCD bifilter8x4_coeff +bifilter8x4_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/common/arm/neon/bilinearpredict8x8_neon.asm b/vp8/common/arm/neon/bilinearpredict8x8_neon.asm new file mode 100644 index 0000000..80728d4 --- /dev/null +++ b/vp8/common/arm/neon/bilinearpredict8x8_neon.asm
@@ -0,0 +1,187 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_bilinear_predict8x8_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_bilinear_predict8x8_neon| PROC + push {r4, lr} + + ldr r12, _bifilter8_coeff_ + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (9x8) + add r2, r12, r2, lsl #3 ;calculate filter location + + vld1.u8 {q1}, [r0], r1 ;load src data + vld1.u32 {d31}, [r2] ;load first_pass filter + vld1.u8 {q2}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {q3}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {q4}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + + vld1.u8 {q1}, [r0], r1 ;load src data + vqrshrn.u16 d22, q6, #7 ;shift/round/saturate to u8 + vld1.u8 {q2}, [r0], r1 + vqrshrn.u16 d23, q7, #7 + vld1.u8 {q3}, [r0], r1 + vqrshrn.u16 d24, q8, #7 + vld1.u8 {q4}, [r0], r1 + vqrshrn.u16 d25, q9, #7 + + ;first_pass filtering on the rest 5-line data + vld1.u8 {q5}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * vp8_filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + vmlal.u8 q10, d11, d1 + + vqrshrn.u16 d26, q6, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d27, q7, #7 + vqrshrn.u16 d28, q8, #7 + vqrshrn.u16 d29, q9, #7 + vqrshrn.u16 d30, q10, #7 + +;Second pass: 8x8 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq skip_secondpass_filter + + add r3, r12, r3, lsl #3 + add r0, r4, lr + + vld1.u32 {d31}, [r3] ;load second_pass filter + add r1, r0, lr + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + + vmull.u8 q1, d22, d0 ;(src_ptr[0] * vp8_filter[0]) + vmull.u8 q2, d23, d0 + vmull.u8 q3, d24, d0 + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d23, d1 ;(src_ptr[pixel_step] * vp8_filter[1]) + vmlal.u8 q2, d24, d1 + vmlal.u8 q3, d25, d1 + vmlal.u8 q4, d26, d1 + vmlal.u8 q5, d27, d1 + vmlal.u8 q6, d28, d1 + vmlal.u8 q7, d29, d1 + vmlal.u8 q8, d30, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2}, [r4] ;store result + vst1.u8 {d3}, [r0] + vst1.u8 {d4}, [r1], lr + vst1.u8 {d5}, [r1], lr + vst1.u8 {d6}, [r1], lr + vst1.u8 {d7}, [r1], lr + vst1.u8 {d8}, [r1], lr + vst1.u8 {d9}, [r1], lr + + pop {r4, pc} + +;-------------------- +skip_firstpass_filter + vld1.u8 {d22}, [r0], r1 ;load src data + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + vld1.u8 {d27}, [r0], r1 + vld1.u8 {d28}, [r0], r1 + vld1.u8 {d29}, [r0], r1 + vld1.u8 {d30}, [r0], r1 + + b secondpass_filter + +;--------------------- +skip_secondpass_filter + vst1.u8 {d22}, [r4], lr ;store result + vst1.u8 {d23}, [r4], lr + vst1.u8 {d24}, [r4], lr + vst1.u8 {d25}, [r4], lr + vst1.u8 {d26}, [r4], lr + vst1.u8 {d27}, [r4], lr + vst1.u8 {d28}, [r4], lr + vst1.u8 {d29}, [r4], lr + + pop {r4, pc} + + ENDP + +;----------------- + AREA bifilters8_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_bifilter8_coeff_ + DCD bifilter8_coeff +bifilter8_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm new file mode 100644 index 0000000..f42ac63 --- /dev/null +++ b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm
@@ -0,0 +1,583 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_build_intra_predictors_mby_neon_func| + EXPORT |vp8_build_intra_predictors_mby_s_neon_func| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *y_buffer +; r1 unsigned char *ypred_ptr +; r2 int y_stride +; r3 int mode +; stack int Up +; stack int Left + +|vp8_build_intra_predictors_mby_neon_func| PROC + push {r4-r8, lr} + + cmp r3, #0 + beq case_dc_pred + cmp r3, #1 + beq case_v_pred + cmp r3, #2 + beq case_h_pred + cmp r3, #3 + beq case_tm_pred + +case_dc_pred + ldr r4, [sp, #24] ; Up + ldr r5, [sp, #28] ; Left + + ; Default the DC average to 128 + mov r12, #128 + vdup.u8 q0, r12 + + ; Zero out running sum + mov r12, #0 + + ; compute shift and jump + adds r7, r4, r5 + beq skip_dc_pred_up_left + + ; Load above row, if it exists + cmp r4, #0 + beq skip_dc_pred_up + + sub r6, r0, r2 + vld1.8 {q1}, [r6] + vpaddl.u8 q2, q1 + vpaddl.u16 q3, q2 + vpaddl.u32 q4, q3 + + vmov.32 r4, d8[0] + vmov.32 r6, d9[0] + + add r12, r4, r6 + + ; Move back to interger registers + +skip_dc_pred_up + + cmp r5, #0 + beq skip_dc_pred_left + + sub r0, r0, #1 + + ; Load left row, if it exists + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0] + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + +skip_dc_pred_left + add r7, r7, #3 ; Shift + sub r4, r7, #1 + mov r5, #1 + add r12, r12, r5, lsl r4 + mov r5, r12, lsr r7 ; expected_dc + + vdup.u8 q0, r5 + +skip_dc_pred_up_left + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + + pop {r4-r8,pc} +case_v_pred + ; Copy down above row + sub r6, r0, r2 + vld1.8 {q0}, [r6] + + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + vst1.u8 {q0}, [r1]! + pop {r4-r8,pc} + +case_h_pred + ; Load 4x yleft_col + sub r0, r0, #1 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + pop {r4-r8,pc} + +case_tm_pred + ; Load yabove_row + sub r3, r0, r2 + vld1.8 {q8}, [r3] + + ; Load ytop_left + sub r3, r3, #1 + ldrb r7, [r3] + + vdup.u16 q7, r7 + + ; Compute yabove_row - ytop_left + mov r3, #1 + vdup.u8 q0, r3 + + vmull.u8 q4, d16, d0 + vmull.u8 q5, d17, d0 + + vsub.s16 q4, q4, q7 + vsub.s16 q5, q5, q7 + + ; Load 4x yleft_col + sub r0, r0, #1 + mov r12, #4 + +case_tm_pred_loop + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u16 q0, r3 + vdup.u16 q1, r4 + vdup.u16 q2, r5 + vdup.u16 q3, r6 + + vqadd.s16 q8, q0, q4 + vqadd.s16 q9, q0, q5 + + vqadd.s16 q10, q1, q4 + vqadd.s16 q11, q1, q5 + + vqadd.s16 q12, q2, q4 + vqadd.s16 q13, q2, q5 + + vqadd.s16 q14, q3, q4 + vqadd.s16 q15, q3, q5 + + vqshrun.s16 d0, q8, #0 + vqshrun.s16 d1, q9, #0 + + vqshrun.s16 d2, q10, #0 + vqshrun.s16 d3, q11, #0 + + vqshrun.s16 d4, q12, #0 + vqshrun.s16 d5, q13, #0 + + vqshrun.s16 d6, q14, #0 + vqshrun.s16 d7, q15, #0 + + vst1.u8 {q0}, [r1]! + vst1.u8 {q1}, [r1]! + vst1.u8 {q2}, [r1]! + vst1.u8 {q3}, [r1]! + + subs r12, r12, #1 + bne case_tm_pred_loop + + pop {r4-r8,pc} + + ENDP + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; r0 unsigned char *y_buffer +; r1 unsigned char *ypred_ptr +; r2 int y_stride +; r3 int mode +; stack int Up +; stack int Left + +|vp8_build_intra_predictors_mby_s_neon_func| PROC + push {r4-r8, lr} + + mov r1, r0 ; unsigned char *ypred_ptr = x->dst.y_buffer; //x->Predictor; + + cmp r3, #0 + beq case_dc_pred_s + cmp r3, #1 + beq case_v_pred_s + cmp r3, #2 + beq case_h_pred_s + cmp r3, #3 + beq case_tm_pred_s + +case_dc_pred_s + ldr r4, [sp, #24] ; Up + ldr r5, [sp, #28] ; Left + + ; Default the DC average to 128 + mov r12, #128 + vdup.u8 q0, r12 + + ; Zero out running sum + mov r12, #0 + + ; compute shift and jump + adds r7, r4, r5 + beq skip_dc_pred_up_left_s + + ; Load above row, if it exists + cmp r4, #0 + beq skip_dc_pred_up_s + + sub r6, r0, r2 + vld1.8 {q1}, [r6] + vpaddl.u8 q2, q1 + vpaddl.u16 q3, q2 + vpaddl.u32 q4, q3 + + vmov.32 r4, d8[0] + vmov.32 r6, d9[0] + + add r12, r4, r6 + + ; Move back to interger registers + +skip_dc_pred_up_s + + cmp r5, #0 + beq skip_dc_pred_left_s + + sub r0, r0, #1 + + ; Load left row, if it exists + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0] + + add r12, r12, r3 + add r12, r12, r4 + add r12, r12, r5 + add r12, r12, r6 + +skip_dc_pred_left_s + add r7, r7, #3 ; Shift + sub r4, r7, #1 + mov r5, #1 + add r12, r12, r5, lsl r4 + mov r5, r12, lsr r7 ; expected_dc + + vdup.u8 q0, r5 + +skip_dc_pred_up_left_s + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + + pop {r4-r8,pc} +case_v_pred_s + ; Copy down above row + sub r6, r0, r2 + vld1.8 {q0}, [r6] + + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q0}, [r1], r2 + pop {r4-r8,pc} + +case_h_pred_s + ; Load 4x yleft_col + sub r0, r0, #1 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u8 q0, r3 + vdup.u8 q1, r4 + vdup.u8 q2, r5 + vdup.u8 q3, r6 + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + pop {r4-r8,pc} + +case_tm_pred_s + ; Load yabove_row + sub r3, r0, r2 + vld1.8 {q8}, [r3] + + ; Load ytop_left + sub r3, r3, #1 + ldrb r7, [r3] + + vdup.u16 q7, r7 + + ; Compute yabove_row - ytop_left + mov r3, #1 + vdup.u8 q0, r3 + + vmull.u8 q4, d16, d0 + vmull.u8 q5, d17, d0 + + vsub.s16 q4, q4, q7 + vsub.s16 q5, q5, q7 + + ; Load 4x yleft_col + sub r0, r0, #1 + mov r12, #4 + +case_tm_pred_loop_s + ldrb r3, [r0], r2 + ldrb r4, [r0], r2 + ldrb r5, [r0], r2 + ldrb r6, [r0], r2 + vdup.u16 q0, r3 + vdup.u16 q1, r4 + vdup.u16 q2, r5 + vdup.u16 q3, r6 + + vqadd.s16 q8, q0, q4 + vqadd.s16 q9, q0, q5 + + vqadd.s16 q10, q1, q4 + vqadd.s16 q11, q1, q5 + + vqadd.s16 q12, q2, q4 + vqadd.s16 q13, q2, q5 + + vqadd.s16 q14, q3, q4 + vqadd.s16 q15, q3, q5 + + vqshrun.s16 d0, q8, #0 + vqshrun.s16 d1, q9, #0 + + vqshrun.s16 d2, q10, #0 + vqshrun.s16 d3, q11, #0 + + vqshrun.s16 d4, q12, #0 + vqshrun.s16 d5, q13, #0 + + vqshrun.s16 d6, q14, #0 + vqshrun.s16 d7, q15, #0 + + vst1.u8 {q0}, [r1], r2 + vst1.u8 {q1}, [r1], r2 + vst1.u8 {q2}, [r1], r2 + vst1.u8 {q3}, [r1], r2 + + subs r12, r12, #1 + bne case_tm_pred_loop_s + + pop {r4-r8,pc} + + ENDP + + + END
diff --git a/vp8/common/arm/neon/copymem16x16_neon.asm b/vp8/common/arm/neon/copymem16x16_neon.asm new file mode 100644 index 0000000..89d5e10 --- /dev/null +++ b/vp8/common/arm/neon/copymem16x16_neon.asm
@@ -0,0 +1,58 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem16x16_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem16x16_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem16x16_neon| PROC + + vld1.u8 {q0}, [r0], r1 + vld1.u8 {q1}, [r0], r1 + vld1.u8 {q2}, [r0], r1 + vst1.u8 {q0}, [r2], r3 + vld1.u8 {q3}, [r0], r1 + vst1.u8 {q1}, [r2], r3 + vld1.u8 {q4}, [r0], r1 + vst1.u8 {q2}, [r2], r3 + vld1.u8 {q5}, [r0], r1 + vst1.u8 {q3}, [r2], r3 + vld1.u8 {q6}, [r0], r1 + vst1.u8 {q4}, [r2], r3 + vld1.u8 {q7}, [r0], r1 + vst1.u8 {q5}, [r2], r3 + vld1.u8 {q8}, [r0], r1 + vst1.u8 {q6}, [r2], r3 + vld1.u8 {q9}, [r0], r1 + vst1.u8 {q7}, [r2], r3 + vld1.u8 {q10}, [r0], r1 + vst1.u8 {q8}, [r2], r3 + vld1.u8 {q11}, [r0], r1 + vst1.u8 {q9}, [r2], r3 + vld1.u8 {q12}, [r0], r1 + vst1.u8 {q10}, [r2], r3 + vld1.u8 {q13}, [r0], r1 + vst1.u8 {q11}, [r2], r3 + vld1.u8 {q14}, [r0], r1 + vst1.u8 {q12}, [r2], r3 + vld1.u8 {q15}, [r0], r1 + vst1.u8 {q13}, [r2], r3 + vst1.u8 {q14}, [r2], r3 + vst1.u8 {q15}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem16x16_neon| + + END
diff --git a/vp8/common/arm/neon/copymem8x4_neon.asm b/vp8/common/arm/neon/copymem8x4_neon.asm new file mode 100644 index 0000000..302f734 --- /dev/null +++ b/vp8/common/arm/neon/copymem8x4_neon.asm
@@ -0,0 +1,33 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x4_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x4_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x4_neon| PROC + vld1.u8 {d0}, [r0], r1 + vld1.u8 {d1}, [r0], r1 + vst1.u8 {d0}, [r2], r3 + vld1.u8 {d2}, [r0], r1 + vst1.u8 {d1}, [r2], r3 + vld1.u8 {d3}, [r0], r1 + vst1.u8 {d2}, [r2], r3 + vst1.u8 {d3}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem8x4_neon| + + END
diff --git a/vp8/common/arm/neon/copymem8x8_neon.asm b/vp8/common/arm/neon/copymem8x8_neon.asm new file mode 100644 index 0000000..50d39ef --- /dev/null +++ b/vp8/common/arm/neon/copymem8x8_neon.asm
@@ -0,0 +1,42 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_copy_mem8x8_neon| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA Block, CODE, READONLY ; name this block of code +;void copy_mem8x8_neon( unsigned char *src, int src_stride, unsigned char *dst, int dst_stride) +;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +|vp8_copy_mem8x8_neon| PROC + + vld1.u8 {d0}, [r0], r1 + vld1.u8 {d1}, [r0], r1 + vst1.u8 {d0}, [r2], r3 + vld1.u8 {d2}, [r0], r1 + vst1.u8 {d1}, [r2], r3 + vld1.u8 {d3}, [r0], r1 + vst1.u8 {d2}, [r2], r3 + vld1.u8 {d4}, [r0], r1 + vst1.u8 {d3}, [r2], r3 + vld1.u8 {d5}, [r0], r1 + vst1.u8 {d4}, [r2], r3 + vld1.u8 {d6}, [r0], r1 + vst1.u8 {d5}, [r2], r3 + vld1.u8 {d7}, [r0], r1 + vst1.u8 {d6}, [r2], r3 + vst1.u8 {d7}, [r2], r3 + + mov pc, lr + + ENDP ; |vp8_copy_mem8x8_neon| + + END
diff --git a/vp8/common/arm/neon/iwalsh_neon.asm b/vp8/common/arm/neon/iwalsh_neon.asm new file mode 100644 index 0000000..4fc744c --- /dev/null +++ b/vp8/common/arm/neon/iwalsh_neon.asm
@@ -0,0 +1,95 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + EXPORT |vp8_short_inv_walsh4x4_neon| + EXPORT |vp8_short_inv_walsh4x4_1_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_inv_walsh4x4_neon(short *input, short *output) +|vp8_short_inv_walsh4x4_neon| PROC + + ; read in all four lines of values: d0->d3 + vldm.64 r0, {q0, q1} + + ; first for loop + + vadd.s16 d4, d0, d3 ;a = [0] + [12] + vadd.s16 d5, d1, d2 ;b = [4] + [8] + vsub.s16 d6, d1, d2 ;c = [4] - [8] + vsub.s16 d7, d0, d3 ;d = [0] - [12] + + vadd.s16 d0, d4, d5 ;a + b + vadd.s16 d1, d6, d7 ;c + d + vsub.s16 d2, d4, d5 ;a - b + vsub.s16 d3, d7, d6 ;d - c + + vtrn.32 d0, d2 ;d0: 0 1 8 9 + ;d2: 2 3 10 11 + vtrn.32 d1, d3 ;d1: 4 5 12 13 + ;d3: 6 7 14 15 + + vtrn.16 d0, d1 ;d0: 0 4 8 12 + ;d1: 1 5 9 13 + vtrn.16 d2, d3 ;d2: 2 6 10 14 + ;d3: 3 7 11 15 + + ; second for loop + + vadd.s16 d4, d0, d3 ;a = [0] + [3] + vadd.s16 d5, d1, d2 ;b = [1] + [2] + vsub.s16 d6, d1, d2 ;c = [1] - [2] + vsub.s16 d7, d0, d3 ;d = [0] - [3] + + vadd.s16 d0, d4, d5 ;e = a + b + vadd.s16 d1, d6, d7 ;f = c + d + vsub.s16 d2, d4, d5 ;g = a - b + vsub.s16 d3, d7, d6 ;h = d - c + + vmov.i16 q2, #3 + vadd.i16 q0, q0, q2 ;e/f += 3 + vadd.i16 q1, q1, q2 ;g/h += 3 + + vshr.s16 q0, q0, #3 ;e/f >> 3 + vshr.s16 q1, q1, #3 ;g/h >> 3 + + vtrn.32 d0, d2 + vtrn.32 d1, d3 + vtrn.16 d0, d1 + vtrn.16 d2, d3 + + vstmia.16 r1!, {q0} + vstmia.16 r1!, {q1} + + bx lr + ENDP ; |vp8_short_inv_walsh4x4_neon| + + +;short vp8_short_inv_walsh4x4_1_neon(short *input, short *output) +|vp8_short_inv_walsh4x4_1_neon| PROC + ; load a full line into a neon register + vld1.16 {q0}, [r0] + ; extract first element and replicate + vdup.16 q1, d0[0] + ; add 3 to all values + vmov.i16 q2, #3 + vadd.i16 q3, q1, q2 + ; right shift + vshr.s16 q3, q3, #3 + ; write it back + vstmia.16 r1!, {q3} + vstmia.16 r1!, {q3} + + bx lr + ENDP ; |vp8_short_inv_walsh4x4_1_neon| + + END
diff --git a/vp8/common/arm/neon/loopfilterhorizontaledge_uv_neon.asm b/vp8/common/arm/neon/loopfilterhorizontaledge_uv_neon.asm new file mode 100644 index 0000000..e3e8e8a --- /dev/null +++ b/vp8/common/arm/neon/loopfilterhorizontaledge_uv_neon.asm
@@ -0,0 +1,205 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_horizontal_edge_uv_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *u, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; stack(r5) unsigned char *v + +|vp8_loop_filter_horizontal_edge_uv_neon| PROC + sub r0, r0, r1, lsl #2 ; move u pointer down by 4 lines + vld1.s8 {d0[], d1[]}, [r2] ; flimit + + ldr r2, [sp, #4] ; load v ptr + ldr r12, [sp, #0] ; load thresh pointer + + sub r2, r2, r1, lsl #2 ; move v pointer down by 4 lines + + vld1.u8 {d6}, [r0], r1 ; p3 + vld1.u8 {d7}, [r2], r1 ; p3 + vld1.u8 {d8}, [r0], r1 ; p2 + vld1.u8 {d9}, [r2], r1 ; p2 + vld1.u8 {d10}, [r0], r1 ; p1 + vld1.u8 {d11}, [r2], r1 ; p1 + vld1.u8 {d12}, [r0], r1 ; p0 + vld1.u8 {d13}, [r2], r1 ; p0 + vld1.u8 {d14}, [r0], r1 ; q0 + vld1.u8 {d15}, [r2], r1 ; q0 + vld1.u8 {d16}, [r0], r1 ; q1 + vld1.u8 {d17}, [r2], r1 ; q1 + vld1.u8 {d18}, [r0], r1 ; q2 + vld1.u8 {d19}, [r2], r1 ; q2 + vld1.u8 {d20}, [r0], r1 ; q3 + vld1.u8 {d21}, [r2], r1 ; q3 + + vld1.s8 {d2[], d3[]}, [r3] ; limit + vld1.s8 {d4[], d5[]}, [r12] ; thresh + + ldr r12, _lfhuv_coeff_ + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) + vabd.u8 q9, q6, q7 ; abs(p0 - q0) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q4, q1, q4 ; (abs(q3 - q2) > limit)*-1 + vadd.u8 q0, q0, q0 ; flimit * 2 + vadd.u8 q0, q0, q1 ; flimit * 2 + limit + + vand q15, q15, q12 + vand q10, q10, q11 + vand q3, q3, q4 + + vabd.u8 q2, q5, q8 ; abs(p1 - q1) + vqadd.u8 q9, q9, q9 ; abs(p0 - q0) * 2 + vshr.u8 q2, q2, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q9, q9, q2 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q9, q0, q9 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + vld1.u8 {q0}, [r12]! + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value +;;;;;;;;;;;;;; + vld1.u8 {q10}, [r12]! + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q11, d15, d13 + + vand q3, q3, q9 + vmovl.u8 q4, d20 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vmul.i8 q2, q2, q10 ; 3 * ( qs0 - ps0) + vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) + vmul.i16 q11, q11, q4 + + vand q1, q1, q14 ; vp8_filter &= hev + vand q15, q15, q3 ; q15: vp8_filter_mask + ;; + ;vld1.u8 {q4}, [r12]! ;no need 7 any more + + ;vqadd.s8 q1, q1, q2 + vaddw.s8 q2, q2, d2 + vaddw.s8 q11, q11, d3 + + vld1.u8 {q9}, [r12]! + ; + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q11 + ;; + + vand q1, q1, q15 ; vp8_filter &= mask + ;; +;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q1, q4 ; s = vp8_filter & 7 +; vqadd.s8 q1, q1, q9 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + ;;;; +; vshr.s8 q1, q1, #3 ; vp8_filter >>= 3 +; vceq.i8 q2, q2, q9 ; s = (s==4)*-1 + ;; +; ;calculate output +; vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) +; vqadd.s8 q11, q2, q1 ; u = vp8_signed_char_clamp(s + vp8_filter) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; q10=3 + vqadd.s8 q2, q1, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q1, q1, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - Filter1) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vrshr.s8 q1, q1, #1 ;round/shift: vp8_filter += 1; vp8_filter >>= 1 + + sub r0, r0, r1, lsl #2 + sub r0, r0, r1, lsl #1 + ; + + vbic q1, q1, q14 ; vp8_filter &= ~hev + + sub r2, r2, r1, lsl #2 + sub r2, r2, r1, lsl #1 + ;; + + vqadd.s8 q13, q5, q1 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + ;vqadd.s8 q11, q6, q11 ; u = vp8_signed_char_clamp(ps0 + u) + vqsub.s8 q12, q8, q1 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + ; + + veor q5, q13, q0 ; *op1 = u^0x80 + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + ; + + vst1.u8 {d10}, [r0], r1 ; store u op1 + vst1.u8 {d11}, [r2], r1 ; store v op1 + vst1.u8 {d12}, [r0], r1 ; store u op0 + vst1.u8 {d13}, [r2], r1 ; store v op0 + vst1.u8 {d14}, [r0], r1 ; store u oq0 + vst1.u8 {d15}, [r2], r1 ; store v oq0 + vst1.u8 {d16}, [r0], r1 ; store u oq1 + vst1.u8 {d17}, [r2], r1 ; store v oq1 + + bx lr + ENDP ; |vp8_loop_filter_horizontal_edge_uv_neon| + +;----------------- + AREA hloopfilteruv_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_lfhuv_coeff_ + DCD lfhuv_coeff +lfhuv_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 + + END
diff --git a/vp8/common/arm/neon/loopfilterhorizontaledge_y_neon.asm b/vp8/common/arm/neon/loopfilterhorizontaledge_y_neon.asm new file mode 100644 index 0000000..f11055d --- /dev/null +++ b/vp8/common/arm/neon/loopfilterhorizontaledge_y_neon.asm
@@ -0,0 +1,188 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_horizontal_edge_y_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused + +|vp8_loop_filter_horizontal_edge_y_neon| PROC + sub r0, r0, r1, lsl #2 ; move src pointer down by 4 lines + ldr r12, [sp, #0] ; load thresh pointer + + vld1.u8 {q3}, [r0], r1 ; p3 + vld1.s8 {d0[], d1[]}, [r2] ; flimit + vld1.u8 {q4}, [r0], r1 ; p2 + vld1.s8 {d2[], d3[]}, [r3] ; limit + vld1.u8 {q5}, [r0], r1 ; p1 + vld1.s8 {d4[], d5[]}, [r12] ; thresh + vld1.u8 {q6}, [r0], r1 ; p0 + ldr r12, _lfhy_coeff_ + vld1.u8 {q7}, [r0], r1 ; q0 + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vld1.u8 {q8}, [r0], r1 ; q1 + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vld1.u8 {q9}, [r0], r1 ; q2 + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vld1.u8 {q10}, [r0], r1 ; q3 + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) + vabd.u8 q9, q6, q7 ; abs(p0 - q0) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q4, q1, q4 ; (abs(q3 - q2) > limit)*-1 + vadd.u8 q0, q0, q0 ; flimit * 2 + vadd.u8 q0, q0, q1 ; flimit * 2 + limit + + vand q15, q15, q12 + vand q10, q10, q11 + vand q3, q3, q4 + + vabd.u8 q2, q5, q8 ; abs(p1 - q1) + vqadd.u8 q9, q9, q9 ; abs(p0 - q0) * 2 + vshr.u8 q2, q2, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q9, q9, q2 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q9, q0, q9 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + vld1.u8 {q0}, [r12]! + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value +;;;;;;;;;;;;;; + vld1.u8 {q10}, [r12]! + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q11, d15, d13 + + vand q3, q3, q9 + vmovl.u8 q4, d20 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vmul.i8 q2, q2, q10 ; 3 * ( qs0 - ps0) + vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) + vmul.i16 q11, q11, q4 + + vand q1, q1, q14 ; vp8_filter &= hev + vand q15, q15, q3 ; q15: vp8_filter_mask + ;; + ;vld1.u8 {q4}, [r12]! ;no need 7 any more + + ;vqadd.s8 q1, q1, q2 + vaddw.s8 q2, q2, d2 + vaddw.s8 q11, q11, d3 + + vld1.u8 {q9}, [r12]! + ; + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q11 + ;; + + vand q1, q1, q15 ; vp8_filter &= mask + ;; +;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q1, q4 ; s = vp8_filter & 7 +; vqadd.s8 q1, q1, q9 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + ;;;; +; vshr.s8 q1, q1, #3 ; vp8_filter >>= 3 +; vceq.i8 q2, q2, q9 ; s = (s==4)*-1 + ;; +; ;calculate output +; vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) +; vqadd.s8 q11, q2, q1 ; u = vp8_signed_char_clamp(s + vp8_filter) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; q10=3 + vqadd.s8 q2, q1, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q1, q1, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - Filter1) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vrshr.s8 q1, q1, #1 ;round/shift: vp8_filter += 1; vp8_filter >>= 1 + + sub r0, r0, r1, lsl #2 + sub r0, r0, r1, lsl #1 + ; + + vbic q1, q1, q14 ; vp8_filter &= ~hev + ; + add r2, r1, r0 + + vqadd.s8 q13, q5, q1 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + ;vqadd.s8 q11, q6, q11 ; u = vp8_signed_char_clamp(ps0 + u) + vqsub.s8 q12, q8, q1 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + + add r3, r2, r1 + + veor q5, q13, q0 ; *op1 = u^0x80 + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + + add r12, r3, r1 + + vst1.u8 {q5}, [r0] ; store op1 + vst1.u8 {q6}, [r2] ; store op0 + vst1.u8 {q7}, [r3] ; store oq0 + vst1.u8 {q8}, [r12] ; store oq1 + + bx lr + ENDP ; |vp8_loop_filter_horizontal_edge_y_neon| + +;----------------- + AREA hloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_lfhy_coeff_ + DCD lfhy_coeff +lfhy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 + + END
diff --git a/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm new file mode 100644 index 0000000..6d74fab --- /dev/null +++ b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm
@@ -0,0 +1,117 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_simple_horizontal_edge_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused + +|vp8_loop_filter_simple_horizontal_edge_neon| PROC + sub r0, r0, r1, lsl #1 ; move src pointer down by 2 lines + + ldr r12, _lfhy_coeff_ + vld1.u8 {q5}, [r0], r1 ; p1 + vld1.s8 {d2[], d3[]}, [r2] ; flimit + vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 + vld1.u8 {q6}, [r0], r1 ; p0 + vld1.u8 {q0}, [r12]! ; 0x80 + vld1.u8 {q7}, [r0], r1 ; q0 + vld1.u8 {q10}, [r12]! ; 0x03 + vld1.u8 {q8}, [r0] ; q1 + + ;vp8_filter_mask() function + vabd.u8 q15, q6, q7 ; abs(p0 - q0) + vabd.u8 q14, q5, q8 ; abs(p1 - q1) + vqadd.u8 q15, q15, q15 ; abs(p0 - q0) * 2 + vshr.u8 q14, q14, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q15, q15, q14 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + + vadd.u8 q1, q1, q1 ; flimit * 2 + vadd.u8 q1, q1, q13 ; flimit * 2 + limit + vcge.u8 q15, q1, q15 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + +;;;;;;;;;; + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q3, d15, d13 + + vqsub.s8 q4, q5, q8 ; q4: vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vmul.i8 q2, q2, q10 ; 3 * ( qs0 - ps0) + vadd.s16 q11, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q12, q3, q3 + + vld1.u8 {q9}, [r12]! ; 0x04 + + vadd.s16 q2, q2, q11 + vadd.s16 q3, q3, q12 + + vaddw.s8 q2, q2, d8 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q3, q3, d9 + + ;vqadd.s8 q4, q4, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d8, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d9, q3 +;;;;;;;;;;;;; + + vand q4, q4, q15 ; vp8_filter &= mask + + vqadd.s8 q2, q4, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q4, q4, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q4, q4, #3 ; Filter1 >>= 3 + + sub r0, r0, r1, lsl #1 + + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q4 ; u = vp8_signed_char_clamp(qs0 - Filter1) + + add r3, r0, r1 + + veor q6, q11, q0 ; *op0 = u^0x80 + veor q7, q10, q0 ; *oq0 = u^0x80 + + vst1.u8 {q6}, [r0] ; store op0 + vst1.u8 {q7}, [r3] ; store oq0 + + bx lr + ENDP ; |vp8_loop_filter_simple_horizontal_edge_neon| + +;----------------- + AREA hloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_lfhy_coeff_ + DCD lfhy_coeff +lfhy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + + END
diff --git a/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm new file mode 100644 index 0000000..2bb6222 --- /dev/null +++ b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm
@@ -0,0 +1,158 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_simple_vertical_edge_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh should be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused + +|vp8_loop_filter_simple_vertical_edge_neon| PROC + sub r0, r0, #2 ; move src pointer down by 2 columns + + vld4.8 {d6[0], d7[0], d8[0], d9[0]}, [r0], r1 + vld1.s8 {d2[], d3[]}, [r2] ; flimit + vld1.s8 {d26[], d27[]}, [r3] ; limit -> q13 + vld4.8 {d6[1], d7[1], d8[1], d9[1]}, [r0], r1 + ldr r12, _vlfy_coeff_ + vld4.8 {d6[2], d7[2], d8[2], d9[2]}, [r0], r1 + vld4.8 {d6[3], d7[3], d8[3], d9[3]}, [r0], r1 + vld4.8 {d6[4], d7[4], d8[4], d9[4]}, [r0], r1 + vld4.8 {d6[5], d7[5], d8[5], d9[5]}, [r0], r1 + vld4.8 {d6[6], d7[6], d8[6], d9[6]}, [r0], r1 + vld4.8 {d6[7], d7[7], d8[7], d9[7]}, [r0], r1 + + vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 + vld1.u8 {q0}, [r12]! ; 0x80 + vld4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1 + vld1.u8 {q11}, [r12]! ; 0x03 + vld4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 + vld1.u8 {q12}, [r12]! ; 0x04 + vld4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1 + vld4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 + vld4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 + vld4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 + vld4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0], r1 + + vswp d7, d10 + vswp d12, d9 + ;vswp q4, q5 ; p1:q3, p0:q5, q0:q4, q1:q6 + + ;vp8_filter_mask() function + ;vp8_hevmask() function + sub r0, r0, r1, lsl #4 + vabd.u8 q15, q5, q4 ; abs(p0 - q0) + vabd.u8 q14, q3, q6 ; abs(p1 - q1) + vqadd.u8 q15, q15, q15 ; abs(p0 - q0) * 2 + vshr.u8 q14, q14, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q15, q15, q14 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + + veor q4, q4, q0 ; qs0: q0 offset to convert to a signed value + veor q5, q5, q0 ; ps0: p0 offset to convert to a signed value + veor q3, q3, q0 ; ps1: p1 offset to convert to a signed value + veor q6, q6, q0 ; qs1: q1 offset to convert to a signed value + + vadd.u8 q1, q1, q1 ; flimit * 2 + vadd.u8 q1, q1, q13 ; flimit * 2 + limit + vcge.u8 q15, q1, q15 ; abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + ;vp8_filter() function +;;;;;;;;;; + ;vqsub.s8 q2, q5, q4 ; ( qs0 - ps0) + vsubl.s8 q2, d8, d10 ; ( qs0 - ps0) + vsubl.s8 q13, d9, d11 + + vqsub.s8 q1, q3, q6 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vmul.i8 q2, q2, q11 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vadd.s16 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q14, q13, q13 + vadd.s16 q2, q2, q10 + vadd.s16 q13, q13, q14 + + ;vqadd.s8 q1, q1, q2 + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q13 + + add r0, r0, #1 + add r2, r0, r1 +;;;;;;;;;;; + + vand q1, q1, q15 ; vp8_filter &= mask + + vqadd.s8 q2, q1, q11 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q1, q1, q12 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + + ;calculate output + vqsub.s8 q10, q4, q1 ; u = vp8_signed_char_clamp(qs0 - Filter1) + vqadd.s8 q11, q5, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q6, q11, q0 ; *op0 = u^0x80 + + add r3, r2, r1 + vswp d13, d14 + add r12, r3, r1 + + ;store op1, op0, oq0, oq1 + vst2.8 {d12[0], d13[0]}, [r0] + vst2.8 {d12[1], d13[1]}, [r2] + vst2.8 {d12[2], d13[2]}, [r3] + vst2.8 {d12[3], d13[3]}, [r12], r1 + add r0, r12, r1 + vst2.8 {d12[4], d13[4]}, [r12] + vst2.8 {d12[5], d13[5]}, [r0], r1 + add r2, r0, r1 + vst2.8 {d12[6], d13[6]}, [r0] + vst2.8 {d12[7], d13[7]}, [r2], r1 + add r3, r2, r1 + vst2.8 {d14[0], d15[0]}, [r2] + vst2.8 {d14[1], d15[1]}, [r3], r1 + add r12, r3, r1 + vst2.8 {d14[2], d15[2]}, [r3] + vst2.8 {d14[3], d15[3]}, [r12], r1 + add r0, r12, r1 + vst2.8 {d14[4], d15[4]}, [r12] + vst2.8 {d14[5], d15[5]}, [r0], r1 + add r2, r0, r1 + vst2.8 {d14[6], d15[6]}, [r0] + vst2.8 {d14[7], d15[7]}, [r2] + + bx lr + ENDP ; |vp8_loop_filter_simple_vertical_edge_neon| + +;----------------- + AREA vloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_vlfy_coeff_ + DCD vlfy_coeff +vlfy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + + END
diff --git a/vp8/common/arm/neon/loopfilterverticaledge_uv_neon.asm b/vp8/common/arm/neon/loopfilterverticaledge_uv_neon.asm new file mode 100644 index 0000000..d79cc68 --- /dev/null +++ b/vp8/common/arm/neon/loopfilterverticaledge_uv_neon.asm
@@ -0,0 +1,231 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_vertical_edge_uv_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *u, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; stack(r5) unsigned char *v + +|vp8_loop_filter_vertical_edge_uv_neon| PROC + sub r0, r0, #4 ; move u pointer down by 4 columns + vld1.s8 {d0[], d1[]}, [r2] ; flimit + + ldr r2, [sp, #4] ; load v ptr + ldr r12, [sp, #0] ; load thresh pointer + + sub r2, r2, #4 ; move v pointer down by 4 columns + + vld1.u8 {d6}, [r0], r1 ;load u data + vld1.u8 {d7}, [r2], r1 ;load v data + vld1.u8 {d8}, [r0], r1 + vld1.u8 {d9}, [r2], r1 + vld1.u8 {d10}, [r0], r1 + vld1.u8 {d11}, [r2], r1 + vld1.u8 {d12}, [r0], r1 + vld1.u8 {d13}, [r2], r1 + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d15}, [r2], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d17}, [r2], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d19}, [r2], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r2], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + vld1.s8 {d2[], d3[]}, [r3] ; limit + vld1.s8 {d4[], d5[]}, [r12] ; thresh + + ldr r12, _vlfuv_coeff_ + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) + vabd.u8 q9, q6, q7 ; abs(p0 - q0) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q4, q1, q4 ; (abs(q3 - q2) > limit)*-1 + vadd.u8 q0, q0, q0 ; flimit * 2 + vadd.u8 q0, q0, q1 ; flimit * 2 + limit + + vand q15, q15, q12 + vand q10, q10, q11 + vand q3, q3, q4 + + vabd.u8 q2, q5, q8 ; abs(p1 - q1) + vqadd.u8 q9, q9, q9 ; abs(p0 - q0) * 2 + vshr.u8 q2, q2, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q9, q9, q2 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q9, q0, q9 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + vld1.u8 {q0}, [r12]! + + vand q15, q15, q10 + + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value +;;;;;;;;;;;;;; + vld1.u8 {q10}, [r12]! + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q11, d15, d13 + + vand q3, q3, q9 + vmovl.u8 q4, d20 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vmul.i8 q2, q2, q10 ; 3 * ( qs0 - ps0) + vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) + vmul.i16 q11, q11, q4 + + vand q1, q1, q14 ; vp8_filter &= hev + vand q15, q15, q3 ; q15: vp8_filter_mask + ;; + ;vld1.u8 {q4}, [r12]! ;no need 7 any more + + ;vqadd.s8 q1, q1, q2 + vaddw.s8 q2, q2, d2 + vaddw.s8 q11, q11, d3 + + vld1.u8 {q9}, [r12]! + ; + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q11 + ;; + + vand q1, q1, q15 ; vp8_filter &= mask + ;; +;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q1, q4 ; s = vp8_filter & 7 +; vqadd.s8 q1, q1, q9 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + ;;;; +; vshr.s8 q1, q1, #3 ; vp8_filter >>= 3 +; vceq.i8 q2, q2, q9 ; s = (s==4)*-1 + ;; +; ;calculate output +; vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) +; vqadd.s8 q11, q2, q1 ; u = vp8_signed_char_clamp(s + vp8_filter) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; q10=3 + vqadd.s8 q2, q1, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q1, q1, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - Filter1) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vrshr.s8 q1, q1, #1 ;round/shift: vp8_filter += 1; vp8_filter >>= 1 + + sub r0, r0, r1, lsl #3 + add r0, r0, #2 + + vbic q1, q1, q14 ; vp8_filter &= ~hev + + sub r2, r2, r1, lsl #3 + add r2, r2, #2 + + vqadd.s8 q13, q5, q1 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + ;vqadd.s8 q11, q6, q11 ; u = vp8_signed_char_clamp(ps0 + u) + vqsub.s8 q12, q8, q1 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q5, q13, q0 ; *op1 = u^0x80 + veor q6, q11, q0 ; *op0 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + + vswp d12, d11 + vswp d16, d13 + vswp d14, d12 + vswp d16, d15 + + ;store op1, op0, oq0, oq1 + vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0], r1 + vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r2], r1 + vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r0], r1 + vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r2], r1 + vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r0], r1 + vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r2], r1 + vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r0], r1 + vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r2], r1 + vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r0], r1 + vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r2], r1 + vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 + vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r2], r1 + vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0], r1 + vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r2], r1 + vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r0], r1 + vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r2], r1 + + bx lr + ENDP ; |vp8_loop_filter_vertical_edge_uv_neon| + +;----------------- + AREA vloopfilteruv_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_vlfuv_coeff_ + DCD vlfuv_coeff +vlfuv_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 + + END
diff --git a/vp8/common/arm/neon/loopfilterverticaledge_y_neon.asm b/vp8/common/arm/neon/loopfilterverticaledge_y_neon.asm new file mode 100644 index 0000000..3a230a9 --- /dev/null +++ b/vp8/common/arm/neon/loopfilterverticaledge_y_neon.asm
@@ -0,0 +1,235 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_loop_filter_vertical_edge_y_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused + +|vp8_loop_filter_vertical_edge_y_neon| PROC + sub r0, r0, #4 ; move src pointer down by 4 columns + ldr r12, [sp, #0] ; load thresh pointer + + vld1.u8 {d6}, [r0], r1 ; load first 8-line src data + vld1.s8 {d0[], d1[]}, [r2] ; flimit + vld1.u8 {d8}, [r0], r1 + vld1.s8 {d2[], d3[]}, [r3] ; limit + vld1.u8 {d10}, [r0], r1 + vld1.s8 {d4[], d5[]}, [r12] ; thresh + vld1.u8 {d12}, [r0], r1 + ldr r12, _vlfy_coeff_ + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d20}, [r0], r1 + + vld1.u8 {d7}, [r0], r1 ; load second 8-line src data + vld1.u8 {d9}, [r0], r1 + vld1.u8 {d11}, [r0], r1 + vld1.u8 {d13}, [r0], r1 + vld1.u8 {d15}, [r0], r1 + vld1.u8 {d17}, [r0], r1 + vld1.u8 {d19}, [r0], r1 + vld1.u8 {d21}, [r0], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q4, q10, q9 ; abs(q3 - q2) + vabd.u8 q9, q6, q7 ; abs(p0 - q0) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q4, q1, q4 ; (abs(q3 - q2) > limit)*-1 + vadd.u8 q0, q0, q0 ; flimit * 2 + vadd.u8 q0, q0, q1 ; flimit * 2 + limit + + vand q15, q15, q12 + vand q10, q10, q11 + vand q3, q3, q4 + + vabd.u8 q2, q5, q8 ; abs(p1 - q1) + vqadd.u8 q9, q9, q9 ; abs(p0 - q0) * 2 + vshr.u8 q2, q2, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q9, q9, q2 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q9, q0, q9 ; (abs(p0 - q0)*2 + abs(p1-q1)/2 > flimit*2 + limit)*-1 + + vld1.u8 {q0}, [r12]! + + vand q15, q15, q10 + + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value +;;;;;;;;;;;;;; + vld1.u8 {q10}, [r12]! + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q11, d15, d13 + + vand q3, q3, q9 + vmovl.u8 q4, d20 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vmul.i8 q2, q2, q10 ; 3 * ( qs0 - ps0) + vmul.i16 q2, q2, q4 ; 3 * ( qs0 - ps0) + vmul.i16 q11, q11, q4 + + vand q1, q1, q14 ; vp8_filter &= hev + vand q15, q15, q3 ; q15: vp8_filter_mask + ;; + ;vld1.u8 {q4}, [r12]! ;no need 7 any more + + ;vqadd.s8 q1, q1, q2 + vaddw.s8 q2, q2, d2 + vaddw.s8 q11, q11, d3 + + vld1.u8 {q9}, [r12]! + ; + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q11 + ;; + + vand q1, q1, q15 ; vp8_filter &= mask + ;; +;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q1, q4 ; s = vp8_filter & 7 +; vqadd.s8 q1, q1, q9 ; vp8_filter = vp8_signed_char_clamp(vp8_filter+4) + ;;;; +; vshr.s8 q1, q1, #3 ; vp8_filter >>= 3 +; vceq.i8 q2, q2, q9 ; s = (s==4)*-1 + ;; +; ;calculate output +; vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - vp8_filter) +; vqadd.s8 q11, q2, q1 ; u = vp8_signed_char_clamp(s + vp8_filter) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; q10=3 + vqadd.s8 q2, q1, q10 ; Filter2 = vp8_signed_char_clamp(vp8_filter+3) + vqadd.s8 q1, q1, q9 ; Filter1 = vp8_signed_char_clamp(vp8_filter+4) + vshr.s8 q2, q2, #3 ; Filter2 >>= 3 + vshr.s8 q1, q1, #3 ; Filter1 >>= 3 + ;calculate output + vqadd.s8 q11, q6, q2 ; u = vp8_signed_char_clamp(ps0 + Filter2) + vqsub.s8 q10, q7, q1 ; u = vp8_signed_char_clamp(qs0 - Filter1) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vrshr.s8 q1, q1, #1 ;round/shift: vp8_filter += 1; vp8_filter >>= 1 + + sub r0, r0, r1, lsl #4 + add r0, r0, #2 + ; + + vbic q1, q1, q14 ; vp8_filter &= ~hev + add r2, r0, r1 + ; + + vqadd.s8 q13, q5, q1 ; u = vp8_signed_char_clamp(ps1 + vp8_filter) + ;vqadd.s8 q11, q6, q11 ; u = vp8_signed_char_clamp(ps0 + u) + vqsub.s8 q12, q8, q1 ; u = vp8_signed_char_clamp(qs1 - vp8_filter) + + veor q7, q10, q0 ; *oq0 = u^0x80 + veor q5, q13, q0 ; *op1 = u^0x80 + veor q6, q11, q0 ; *op0 = u^0x80 + veor q8, q12, q0 ; *oq1 = u^0x80 + add r3, r2, r1 + ; + vswp d12, d11 + vswp d16, d13 + add r12, r3, r1 + vswp d14, d12 + vswp d16, d15 + + ;store op1, op0, oq0, oq1 + vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [r0] + vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [r2] + vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [r3] + vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [r12], r1 + add r0, r12, r1 + vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [r12] + vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [r0], r1 + add r2, r0, r1 + vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [r0] + vst4.8 {d10[7], d11[7], d12[7], d13[7]}, [r2], r1 + add r3, r2, r1 + vst4.8 {d14[0], d15[0], d16[0], d17[0]}, [r2] + vst4.8 {d14[1], d15[1], d16[1], d17[1]}, [r3], r1 + add r12, r3, r1 + vst4.8 {d14[2], d15[2], d16[2], d17[2]}, [r3] + vst4.8 {d14[3], d15[3], d16[3], d17[3]}, [r12], r1 + add r0, r12, r1 + vst4.8 {d14[4], d15[4], d16[4], d17[4]}, [r12] + vst4.8 {d14[5], d15[5], d16[5], d17[5]}, [r0], r1 + add r2, r0, r1 + vst4.8 {d14[6], d15[6], d16[6], d17[6]}, [r0] + vst4.8 {d14[7], d15[7], d16[7], d17[7]}, [r2] + + bx lr + ENDP ; |vp8_loop_filter_vertical_edge_y_neon| + +;----------------- + AREA vloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_vlfy_coeff_ + DCD vlfy_coeff +vlfy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x01010101, 0x01010101, 0x01010101, 0x01010101 + + END
diff --git a/vp8/common/arm/neon/mbloopfilterhorizontaledge_uv_neon.asm b/vp8/common/arm/neon/mbloopfilterhorizontaledge_uv_neon.asm new file mode 100644 index 0000000..86eddaa --- /dev/null +++ b/vp8/common/arm/neon/mbloopfilterhorizontaledge_uv_neon.asm
@@ -0,0 +1,257 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_mbloop_filter_horizontal_edge_uv_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *u, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; stack(r5) unsigned char *v +|vp8_mbloop_filter_horizontal_edge_uv_neon| PROC + sub r0, r0, r1, lsl #2 ; move u pointer down by 4 lines + vld1.s8 {d2[], d3[]}, [r3] ; limit + ldr r3, [sp, #4] ; load v ptr + ldr r12, [sp, #0] ; load thresh pointer + sub r3, r3, r1, lsl #2 ; move v pointer down by 4 lines + + vld1.u8 {d6}, [r0], r1 ; p3 + vld1.u8 {d7}, [r3], r1 ; p3 + vld1.u8 {d8}, [r0], r1 ; p2 + vld1.u8 {d9}, [r3], r1 ; p2 + vld1.u8 {d10}, [r0], r1 ; p1 + vld1.u8 {d11}, [r3], r1 ; p1 + vld1.u8 {d12}, [r0], r1 ; p0 + vld1.u8 {d13}, [r3], r1 ; p0 + vld1.u8 {d14}, [r0], r1 ; q0 + vld1.u8 {d15}, [r3], r1 ; q0 + vld1.u8 {d16}, [r0], r1 ; q1 + vld1.u8 {d17}, [r3], r1 ; q1 + vld1.u8 {d18}, [r0], r1 ; q2 + vld1.u8 {d19}, [r3], r1 ; q2 + vld1.u8 {d20}, [r0], r1 ; q3 + vld1.u8 {d21}, [r3], r1 ; q3 + + vld1.s8 {d4[], d5[]}, [r12] ; thresh + + ldr r12, _mbhlfuv_coeff_ + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q0, q1, q0 ; (abs(q3 - q2) > limit)*-1 + + vand q15, q15, q12 + + vabd.u8 q12, q6, q7 ; abs(p0 - q0) + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vld1.s8 {d4[], d5[]}, [r2] ; flimit + + vand q10, q10, q11 + vand q3, q3, q0 + + vld1.u8 {q0}, [r12]! + + vadd.u8 q2, q2, q2 ; flimit * 2 + vadd.u8 q2, q2, q1 ; flimit * 2 + limit + + vabd.u8 q1, q5, q8 ; abs(p1 - q1) + vqadd.u8 q12, q12, q12 ; abs(p0 - q0) * 2 + vshr.u8 q1, q1, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q12, q12, q1 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q12, q2, q12 ; (abs(p0 - q0)*2 + abs(p1 - q1)/2 > flimit*2 + limit)*-1 + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + veor q4, q4, q0 ; ps2: p2 offset to convert to a signed value + veor q9, q9, q0 ; qs2: q2 offset to convert to a signed value +;;;;;;;;;;;;; + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q13, d15, d13 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vadd.s8 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q11, q13, q13 + + vand q3, q3, q12 + + ;vadd.s8 q2, q2, q10 + vadd.s16 q2, q2, q10 + vadd.s16 q13, q13, q11 + + vld1.u8 {q12}, [r12]! ;#3 + + ;vqadd.s8 q1, q1, q2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vand q15, q15, q3 ; q15: vp8_filter_mask + vld1.u8 {q11}, [r12]! ;#4 + + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q13 + +;;;;;;;;;;;;;; + vand q1, q1, q15 ; vp8_filter &= mask + + vld1.u8 {q15}, [r12]! ;#63 + ; + vand q13, q1, q14 ; Filter2: q13; Filter2 &= hev + + vld1.u8 {d7}, [r12]! ;#9 + ; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q13, q12 ; s = Filter2 & 7 + +; vqadd.s8 q13, q13, q11 ; Filter2 = vp8_signed_char_clamp(Filter2+4) +; vld1.u8 {d6}, [r12]! ;#18 + +; sub r0, r0, r1, lsl #3 +; sub r3, r3, r1, lsl #3 + +; vshr.s8 q13, q13, #3 ; Filter2 >>= 3 +; vceq.i8 q2, q2, q11 ; s = (s==4)*-1 + +; add r0, r0, r1 +; add r3, r3, r1 + +; vqsub.s8 q7, q7, q13 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) +; vqadd.s8 q11, q2, q13 ; u = vp8_signed_char_clamp(s + Filter2) + +; vld1.u8 {d5}, [r12]! ;#27 +; vmov q10, q15 +; vmov q12, q15 + +; vqadd.s8 q6, q6, q11 ; ps0 = vp8_signed_char_clamp(ps0 + u) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + vqadd.s8 q2, q13, q11 ; Filter1 = vp8_signed_char_clamp(Filter2+4) + vqadd.s8 q13, q13, q12 ; Filter2 = vp8_signed_char_clamp(Filter2+3) + + vld1.u8 {d6}, [r12]! ;#18 + + sub r0, r0, r1, lsl #3 + sub r3, r3, r1, lsl #3 + + vshr.s8 q2, q2, #3 ; Filter1 >>= 3 + vshr.s8 q13, q13, #3 ; Filter2 >>= 3 + + vmov q10, q15 + vmov q12, q15 + + vqsub.s8 q7, q7, q2 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + + vld1.u8 {d5}, [r12]! ;#27 + + add r0, r0, r1 + add r3, r3, r1 + + vqadd.s8 q6, q6, q13 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vbic q1, q1, q14 ; Filter2: q1; vp8_filter &= ~hev; Filter2 = vp8_filter + + ; roughly 1/7th difference across boundary + ; roughly 2/7th difference across boundary + ; roughly 3/7th difference across boundary + vmov q11, q15 + vmov q13, q15 + vmov q14, q15 + + vmlal.s8 q10, d2, d7 ; Filter2 * 9 + vmlal.s8 q11, d3, d7 + vmlal.s8 q12, d2, d6 ; Filter2 * 18 + vmlal.s8 q13, d3, d6 + vmlal.s8 q14, d2, d5 ; Filter2 * 27 + vmlal.s8 q15, d3, d5 + vqshrn.s16 d20, q10, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + vqshrn.s16 d21, q11, #7 + vqshrn.s16 d24, q12, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + vqshrn.s16 d25, q13, #7 + vqshrn.s16 d28, q14, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + vqshrn.s16 d29, q15, #7 + + vqsub.s8 q11, q9, q10 ; s = vp8_signed_char_clamp(qs2 - u) + vqadd.s8 q10, q4, q10 ; s = vp8_signed_char_clamp(ps2 + u) + vqsub.s8 q13, q8, q12 ; s = vp8_signed_char_clamp(qs1 - u) + vqadd.s8 q12, q5, q12 ; s = vp8_signed_char_clamp(ps1 + u) + vqsub.s8 q15, q7, q14 ; s = vp8_signed_char_clamp(qs0 - u) + vqadd.s8 q14, q6, q14 ; s = vp8_signed_char_clamp(ps0 + u) + veor q9, q11, q0 ; *oq2 = s^0x80 + veor q4, q10, q0 ; *op2 = s^0x80 + veor q8, q13, q0 ; *oq1 = s^0x80 + veor q5, q12, q0 ; *op2 = s^0x80 + veor q7, q15, q0 ; *oq0 = s^0x80 + veor q6, q14, q0 ; *op0 = s^0x80 + + vst1.u8 {d8}, [r0], r1 ; store u op2 + vst1.u8 {d9}, [r3], r1 ; store v op2 + vst1.u8 {d10}, [r0], r1 ; store u op1 + vst1.u8 {d11}, [r3], r1 ; store v op1 + vst1.u8 {d12}, [r0], r1 ; store u op0 + vst1.u8 {d13}, [r3], r1 ; store v op0 + vst1.u8 {d14}, [r0], r1 ; store u oq0 + vst1.u8 {d15}, [r3], r1 ; store v oq0 + vst1.u8 {d16}, [r0], r1 ; store u oq1 + vst1.u8 {d17}, [r3], r1 ; store v oq1 + vst1.u8 {d18}, [r0], r1 ; store u oq2 + vst1.u8 {d19}, [r3], r1 ; store v oq2 + + bx lr + ENDP ; |vp8_mbloop_filter_horizontal_edge_uv_neon| + +;----------------- + AREA mbhloopfilteruv_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_mbhlfuv_coeff_ + DCD mbhlfuv_coeff +mbhlfuv_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x003f003f, 0x003f003f, 0x003f003f, 0x003f003f + DCD 0x09090909, 0x09090909, 0x12121212, 0x12121212 + DCD 0x1b1b1b1b, 0x1b1b1b1b + + END
diff --git a/vp8/common/arm/neon/mbloopfilterhorizontaledge_y_neon.asm b/vp8/common/arm/neon/mbloopfilterhorizontaledge_y_neon.asm new file mode 100644 index 0000000..2ab0fc2 --- /dev/null +++ b/vp8/common/arm/neon/mbloopfilterhorizontaledge_y_neon.asm
@@ -0,0 +1,236 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_mbloop_filter_horizontal_edge_y_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused +|vp8_mbloop_filter_horizontal_edge_y_neon| PROC + sub r0, r0, r1, lsl #2 ; move src pointer down by 4 lines + ldr r12, [sp, #0] ; load thresh pointer + + vld1.u8 {q3}, [r0], r1 ; p3 + vld1.s8 {d2[], d3[]}, [r3] ; limit + vld1.u8 {q4}, [r0], r1 ; p2 + vld1.s8 {d4[], d5[]}, [r12] ; thresh + vld1.u8 {q5}, [r0], r1 ; p1 + ldr r12, _mbhlfy_coeff_ + vld1.u8 {q6}, [r0], r1 ; p0 + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vld1.u8 {q7}, [r0], r1 ; q0 + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vld1.u8 {q8}, [r0], r1 ; q1 + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vld1.u8 {q9}, [r0], r1 ; q2 + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vld1.u8 {q10}, [r0], r1 ; q3 + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q0, q1, q0 ; (abs(q3 - q2) > limit)*-1 + + vand q15, q15, q12 + + vabd.u8 q12, q6, q7 ; abs(p0 - q0) + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vld1.s8 {d4[], d5[]}, [r2] ; flimit + + vand q10, q10, q11 + vand q3, q3, q0 + + vld1.u8 {q0}, [r12]! + + vadd.u8 q2, q2, q2 ; flimit * 2 + vadd.u8 q2, q2, q1 ; flimit * 2 + limit + + vabd.u8 q1, q5, q8 ; abs(p1 - q1) + vqadd.u8 q12, q12, q12 ; abs(p0 - q0) * 2 + vshr.u8 q1, q1, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q12, q12, q1 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q12, q2, q12 ; (abs(p0 - q0)*2 + abs(p1 - q1)/2 > flimit*2 + limit)*-1 + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + veor q4, q4, q0 ; ps2: p2 offset to convert to a signed value + veor q9, q9, q0 ; qs2: q2 offset to convert to a signed value +;;;;;;;;;;;;; + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q13, d15, d13 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vadd.s8 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q11, q13, q13 + + vand q3, q3, q12 + + ;vadd.s8 q2, q2, q10 + vadd.s16 q2, q2, q10 + vadd.s16 q13, q13, q11 + + vld1.u8 {q12}, [r12]! ;#3 + + ;vqadd.s8 q1, q1, q2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vand q15, q15, q3 ; q15: vp8_filter_mask + vld1.u8 {q11}, [r12]! ;#4 + + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q13 + +;;;;;;;;;;;;;; + vand q1, q1, q15 ; vp8_filter &= mask + + vld1.u8 {q15}, [r12]! ;#63 + ; + vand q13, q1, q14 ; Filter2: q13; Filter2 &= hev + + vld1.u8 {d7}, [r12]! ;#9 + sub r0, r0, r1, lsl #3 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q13, q12 ; s = Filter2 & 7 + +; vqadd.s8 q13, q13, q11 ; Filter2 = vp8_signed_char_clamp(Filter2+4) +; vld1.u8 {d6}, [r12]! ;#18 + +; add r0, r0, r1 +; add r2, r0, r1 + +; vshr.s8 q13, q13, #3 ; Filter2 >>= 3 +; vceq.i8 q2, q2, q11 ; s = (s==4)*-1 + +; add r3, r2, r1 + +; vqsub.s8 q7, q7, q13 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) +; vqadd.s8 q11, q2, q13 ; u = vp8_signed_char_clamp(s + Filter2) + +; vld1.u8 {d5}, [r12]! ;#27 +; vmov q10, q15 +; vmov q12, q15 + +; vqadd.s8 q6, q6, q11 ; ps0 = vp8_signed_char_clamp(ps0 + u) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + vqadd.s8 q2, q13, q11 ; Filter1 = vp8_signed_char_clamp(Filter2+4) + vqadd.s8 q13, q13, q12 ; Filter2 = vp8_signed_char_clamp(Filter2+3) + + vld1.u8 {d6}, [r12]! ;#18 + add r0, r0, r1 + add r2, r0, r1 + + vshr.s8 q2, q2, #3 ; Filter1 >>= 3 + vshr.s8 q13, q13, #3 ; Filter2 >>= 3 + + vmov q10, q15 + vmov q12, q15 + + vqsub.s8 q7, q7, q2 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + + vld1.u8 {d5}, [r12]! ;#27 + add r3, r2, r1 + + vqadd.s8 q6, q6, q13 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vbic q1, q1, q14 ; Filter2: q1; vp8_filter &= ~hev; Filter2 = vp8_filter + + ; roughly 1/7th difference across boundary + ; roughly 2/7th difference across boundary + ; roughly 3/7th difference across boundary + vmov q11, q15 + vmov q13, q15 + vmov q14, q15 + + vmlal.s8 q10, d2, d7 ; Filter2 * 9 + vmlal.s8 q11, d3, d7 + vmlal.s8 q12, d2, d6 ; Filter2 * 18 + vmlal.s8 q13, d3, d6 + vmlal.s8 q14, d2, d5 ; Filter2 * 27 + vmlal.s8 q15, d3, d5 + vqshrn.s16 d20, q10, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + vqshrn.s16 d21, q11, #7 + vqshrn.s16 d24, q12, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + vqshrn.s16 d25, q13, #7 + vqshrn.s16 d28, q14, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + vqshrn.s16 d29, q15, #7 + + vqsub.s8 q11, q9, q10 ; s = vp8_signed_char_clamp(qs2 - u) + vqadd.s8 q10, q4, q10 ; s = vp8_signed_char_clamp(ps2 + u) + vqsub.s8 q13, q8, q12 ; s = vp8_signed_char_clamp(qs1 - u) + vqadd.s8 q12, q5, q12 ; s = vp8_signed_char_clamp(ps1 + u) + vqsub.s8 q15, q7, q14 ; s = vp8_signed_char_clamp(qs0 - u) + vqadd.s8 q14, q6, q14 ; s = vp8_signed_char_clamp(ps0 + u) + veor q9, q11, q0 ; *oq2 = s^0x80 + veor q4, q10, q0 ; *op2 = s^0x80 + veor q5, q12, q0 ; *op2 = s^0x80 + veor q6, q14, q0 ; *op0 = s^0x80 + veor q8, q13, q0 ; *oq1 = s^0x80 + veor q7, q15, q0 ; *oq0 = s^0x80 + + vst1.u8 {q4}, [r0] ; store op2 + vst1.u8 {q5}, [r2] ; store op1 + vst1.u8 {q6}, [r3], r1 ; store op0 + add r12, r3, r1 + vst1.u8 {q7}, [r3] ; store oq0 + vst1.u8 {q8}, [r12], r1 ; store oq1 + vst1.u8 {q9}, [r12] ; store oq2 + + bx lr + ENDP ; |vp8_mbloop_filter_horizontal_edge_y_neon| + +;----------------- + AREA mbhloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_mbhlfy_coeff_ + DCD mbhlfy_coeff +mbhlfy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x003f003f, 0x003f003f, 0x003f003f, 0x003f003f + DCD 0x09090909, 0x09090909, 0x12121212, 0x12121212 + DCD 0x1b1b1b1b, 0x1b1b1b1b + + END
diff --git a/vp8/common/arm/neon/mbloopfilterverticaledge_uv_neon.asm b/vp8/common/arm/neon/mbloopfilterverticaledge_uv_neon.asm new file mode 100644 index 0000000..ad5afba --- /dev/null +++ b/vp8/common/arm/neon/mbloopfilterverticaledge_uv_neon.asm
@@ -0,0 +1,296 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_mbloop_filter_vertical_edge_uv_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *u, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; stack(r5) unsigned char *v +|vp8_mbloop_filter_vertical_edge_uv_neon| PROC + sub r0, r0, #4 ; move src pointer down by 4 columns + vld1.s8 {d2[], d3[]}, [r3] ; limit + ldr r3, [sp, #4] ; load v ptr + ldr r12, [sp, #0] ; load thresh pointer + + sub r3, r3, #4 ; move v pointer down by 4 columns + + vld1.u8 {d6}, [r0], r1 ;load u data + vld1.u8 {d7}, [r3], r1 ;load v data + vld1.u8 {d8}, [r0], r1 + vld1.u8 {d9}, [r3], r1 + vld1.u8 {d10}, [r0], r1 + vld1.u8 {d11}, [r3], r1 + vld1.u8 {d12}, [r0], r1 + vld1.u8 {d13}, [r3], r1 + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d15}, [r3], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d17}, [r3], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d19}, [r3], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r3], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + sub sp, sp, #32 + vld1.s8 {d4[], d5[]}, [r12] ; thresh + vst1.u8 {q3}, [sp]! + ldr r12, _mbvlfuv_coeff_ + vst1.u8 {q10}, [sp]! + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q0, q1, q0 ; (abs(q3 - q2) > limit)*-1 + + vand q15, q15, q12 + + vabd.u8 q12, q6, q7 ; abs(p0 - q0) + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vld1.s8 {d4[], d5[]}, [r2] ; flimit + + vand q10, q10, q11 + vand q3, q3, q0 + + vld1.u8 {q0}, [r12]! + + vadd.u8 q2, q2, q2 ; flimit * 2 + vadd.u8 q2, q2, q1 ; flimit * 2 + limit + + vabd.u8 q1, q5, q8 ; abs(p1 - q1) + vqadd.u8 q12, q12, q12 ; abs(p0 - q0) * 2 + vshr.u8 q1, q1, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q12, q12, q1 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q12, q2, q12 ; (abs(p0 - q0)*2 + abs(p1 - q1)/2 > flimit*2 + limit)*-1 + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + veor q4, q4, q0 ; ps2: p2 offset to convert to a signed value + veor q9, q9, q0 ; qs2: q2 offset to convert to a signed value +;;;;;;;;;;;;; + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q13, d15, d13 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vadd.s8 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q11, q13, q13 + + vand q3, q3, q12 + + ;vadd.s8 q2, q2, q10 + vadd.s16 q2, q2, q10 + vadd.s16 q13, q13, q11 + + vld1.u8 {q12}, [r12]! ;#3 + + ;vqadd.s8 q1, q1, q2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vand q15, q15, q3 ; q15: vp8_filter_mask + vld1.u8 {q11}, [r12]! ;#4 + + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q13 + +;;;;;;;;;;;;;; + vand q1, q1, q15 ; vp8_filter &= mask + + vld1.u8 {q15}, [r12]! ;#63 + ; + vand q13, q1, q14 ; Filter2: q13; Filter2 &= hev + + vld1.u8 {d7}, [r12]! ;#9 + ; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q13, q12 ; s = Filter2 & 7 + +; vqadd.s8 q13, q13, q11 ; Filter2 = vp8_signed_char_clamp(Filter2+4) +; vld1.u8 {d6}, [r12]! ;#18 + +; sub r0, r0, r1, lsl #3 +; sub r3, r3, r1, lsl #3 +; sub sp, sp, #32 + +; vshr.s8 q13, q13, #3 ; Filter2 >>= 3 +; vceq.i8 q2, q2, q11 ; s = (s==4)*-1 + +; vqsub.s8 q7, q7, q13 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) +; vqadd.s8 q11, q2, q13 ; u = vp8_signed_char_clamp(s + Filter2) + +; vld1.u8 {d5}, [r12]! ;#27 +; vmov q10, q15 +; vmov q12, q15 + +; vqadd.s8 q6, q6, q11 ; ps0 = vp8_signed_char_clamp(ps0 + u) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + vqadd.s8 q2, q13, q11 ; Filter1 = vp8_signed_char_clamp(Filter2+4) + vqadd.s8 q13, q13, q12 ; Filter2 = vp8_signed_char_clamp(Filter2+3) + + vld1.u8 {d6}, [r12]! ;#18 + + sub r0, r0, r1, lsl #3 + sub r3, r3, r1, lsl #3 + + vshr.s8 q2, q2, #3 ; Filter1 >>= 3 + vshr.s8 q13, q13, #3 ; Filter2 >>= 3 + + vmov q10, q15 + vmov q12, q15 + + vqsub.s8 q7, q7, q2 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + + vld1.u8 {d5}, [r12]! ;#27 + + sub sp, sp, #32 + + vqadd.s8 q6, q6, q13 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vbic q1, q1, q14 ; Filter2: q1; vp8_filter &= ~hev; Filter2 = vp8_filter + + ; roughly 1/7th difference across boundary + ; roughly 2/7th difference across boundary + ; roughly 3/7th difference across boundary + vmov q11, q15 + vmov q13, q15 + vmov q14, q15 + + vmlal.s8 q10, d2, d7 ; Filter2 * 9 + vmlal.s8 q11, d3, d7 + vmlal.s8 q12, d2, d6 ; Filter2 * 18 + vmlal.s8 q13, d3, d6 + vmlal.s8 q14, d2, d5 ; Filter2 * 27 + vmlal.s8 q15, d3, d5 + vqshrn.s16 d20, q10, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + vqshrn.s16 d21, q11, #7 + vqshrn.s16 d24, q12, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + vqshrn.s16 d25, q13, #7 + vqshrn.s16 d28, q14, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + vqshrn.s16 d29, q15, #7 + + vqsub.s8 q11, q9, q10 ; s = vp8_signed_char_clamp(qs2 - u) + vqadd.s8 q10, q4, q10 ; s = vp8_signed_char_clamp(ps2 + u) + vqsub.s8 q13, q8, q12 ; s = vp8_signed_char_clamp(qs1 - u) + vqadd.s8 q12, q5, q12 ; s = vp8_signed_char_clamp(ps1 + u) + vqsub.s8 q15, q7, q14 ; s = vp8_signed_char_clamp(qs0 - u) + vqadd.s8 q14, q6, q14 ; s = vp8_signed_char_clamp(ps0 + u) + veor q9, q11, q0 ; *oq2 = s^0x80 + veor q4, q10, q0 ; *op2 = s^0x80 + veor q8, q13, q0 ; *oq1 = s^0x80 + veor q5, q12, q0 ; *op2 = s^0x80 + veor q7, q15, q0 ; *oq0 = s^0x80 + vld1.u8 {q3}, [sp]! + veor q6, q14, q0 ; *op0 = s^0x80 + vld1.u8 {q10}, [sp]! + + ;transpose to 16x8 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + ;store op2, op1, op0, oq0, oq1, oq2 + vst1.8 {d6}, [r0], r1 + vst1.8 {d7}, [r3], r1 + vst1.8 {d8}, [r0], r1 + vst1.8 {d9}, [r3], r1 + vst1.8 {d10}, [r0], r1 + vst1.8 {d11}, [r3], r1 + vst1.8 {d12}, [r0], r1 + vst1.8 {d13}, [r3], r1 + vst1.8 {d14}, [r0], r1 + vst1.8 {d15}, [r3], r1 + vst1.8 {d16}, [r0], r1 + vst1.8 {d17}, [r3], r1 + vst1.8 {d18}, [r0], r1 + vst1.8 {d19}, [r3], r1 + vst1.8 {d20}, [r0], r1 + vst1.8 {d21}, [r3], r1 + + bx lr + ENDP ; |vp8_mbloop_filter_vertical_edge_uv_neon| + +;----------------- + AREA mbvloopfilteruv_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_mbvlfuv_coeff_ + DCD mbvlfuv_coeff +mbvlfuv_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x003f003f, 0x003f003f, 0x003f003f, 0x003f003f + DCD 0x09090909, 0x09090909, 0x12121212, 0x12121212 + DCD 0x1b1b1b1b, 0x1b1b1b1b + + END
diff --git a/vp8/common/arm/neon/mbloopfilterverticaledge_y_neon.asm b/vp8/common/arm/neon/mbloopfilterverticaledge_y_neon.asm new file mode 100644 index 0000000..60e5175 --- /dev/null +++ b/vp8/common/arm/neon/mbloopfilterverticaledge_y_neon.asm
@@ -0,0 +1,303 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_mbloop_filter_vertical_edge_y_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;Note: flimit, limit, and thresh shpuld be positive numbers. All 16 elements in flimit +;are equal. So, in the code, only one load is needed +;for flimit. Same way applies to limit and thresh. +; r0 unsigned char *s, +; r1 int p, //pitch +; r2 const signed char *flimit, +; r3 const signed char *limit, +; stack(r4) const signed char *thresh, +; //stack(r5) int count --unused +|vp8_mbloop_filter_vertical_edge_y_neon| PROC + sub r0, r0, #4 ; move src pointer down by 4 columns + + vld1.u8 {d6}, [r0], r1 ; load first 8-line src data + ldr r12, [sp, #0] ; load thresh pointer + vld1.u8 {d8}, [r0], r1 + sub sp, sp, #32 + vld1.u8 {d10}, [r0], r1 + vld1.u8 {d12}, [r0], r1 + vld1.u8 {d14}, [r0], r1 + vld1.u8 {d16}, [r0], r1 + vld1.u8 {d18}, [r0], r1 + vld1.u8 {d20}, [r0], r1 + + vld1.u8 {d7}, [r0], r1 ; load second 8-line src data + vld1.u8 {d9}, [r0], r1 + vld1.u8 {d11}, [r0], r1 + vld1.u8 {d13}, [r0], r1 + vld1.u8 {d15}, [r0], r1 + vld1.u8 {d17}, [r0], r1 + vld1.u8 {d19}, [r0], r1 + vld1.u8 {d21}, [r0], r1 + + ;transpose to 8x16 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + vld1.s8 {d2[], d3[]}, [r3] ; limit + vst1.u8 {q3}, [sp]! + vld1.s8 {d4[], d5[]}, [r12] ; thresh + ldr r12, _mbvlfy_coeff_ + vst1.u8 {q10}, [sp]! + + ;vp8_filter_mask() function + ;vp8_hevmask() function + vabd.u8 q11, q3, q4 ; abs(p3 - p2) + vabd.u8 q12, q4, q5 ; abs(p2 - p1) + vabd.u8 q13, q5, q6 ; abs(p1 - p0) + vabd.u8 q14, q8, q7 ; abs(q1 - q0) + vabd.u8 q3, q9, q8 ; abs(q2 - q1) + vabd.u8 q0, q10, q9 ; abs(q3 - q2) + + vcge.u8 q15, q1, q11 ; (abs(p3 - p2) > limit)*-1 + vcge.u8 q12, q1, q12 ; (abs(p2 - p1) > limit)*-1 + vcge.u8 q10, q1, q13 ; (abs(p1 - p0) > limit)*-1 + vcge.u8 q11, q1, q14 ; (abs(q1 - q0) > limit)*-1 + vcge.u8 q3, q1, q3 ; (abs(q2 - q1) > limit)*-1 + vcge.u8 q0, q1, q0 ; (abs(q3 - q2) > limit)*-1 + + vand q15, q15, q12 + + vabd.u8 q12, q6, q7 ; abs(p0 - q0) + + vcgt.u8 q13, q13, q2 ; (abs(p1 - p0) > thresh)*-1 + vcgt.u8 q14, q14, q2 ; (abs(q1 - q0) > thresh)*-1 + + vld1.s8 {d4[], d5[]}, [r2] ; flimit + + vand q10, q10, q11 + vand q3, q3, q0 + + vld1.u8 {q0}, [r12]! + + vadd.u8 q2, q2, q2 ; flimit * 2 + vadd.u8 q2, q2, q1 ; flimit * 2 + limit + + vabd.u8 q1, q5, q8 ; abs(p1 - q1) + vqadd.u8 q12, q12, q12 ; abs(p0 - q0) * 2 + vshr.u8 q1, q1, #1 ; abs(p1 - q1) / 2 + vqadd.u8 q12, q12, q1 ; abs(p0 - q0) * 2 + abs(p1 - q1) / 2 + vcge.u8 q12, q2, q12 ; (abs(p0 - q0)*2 + abs(p1 - q1)/2 > flimit*2 + limit)*-1 + + vand q15, q15, q10 + + ;vp8_filter() function + veor q7, q7, q0 ; qs0: q0 offset to convert to a signed value + veor q6, q6, q0 ; ps0: p0 offset to convert to a signed value + veor q5, q5, q0 ; ps1: p1 offset to convert to a signed value + veor q8, q8, q0 ; qs1: q1 offset to convert to a signed value + veor q4, q4, q0 ; ps2: p2 offset to convert to a signed value + veor q9, q9, q0 ; qs2: q2 offset to convert to a signed value +;;;;;;;;;;;;; + vorr q14, q13, q14 ; q14: vp8_hevmask + + ;vqsub.s8 q2, q7, q6 ; ( qs0 - ps0) + vsubl.s8 q2, d14, d12 ; ( qs0 - ps0) + vsubl.s8 q13, d15, d13 + + vqsub.s8 q1, q5, q8 ; vp8_filter = vp8_signed_char_clamp(ps1-qs1) + + ;vadd.s8 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q10, q2, q2 ; 3 * ( qs0 - ps0) + vadd.s16 q11, q13, q13 + + vand q3, q3, q12 + + ;vadd.s8 q2, q2, q10 + vadd.s16 q2, q2, q10 + vadd.s16 q13, q13, q11 + + vld1.u8 {q12}, [r12]! ;#3 + + ;vqadd.s8 q1, q1, q2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q2, q2, d2 ; vp8_filter + 3 * ( qs0 - ps0) + vaddw.s8 q13, q13, d3 + + vand q15, q15, q3 ; q15: vp8_filter_mask + vld1.u8 {q11}, [r12]! ;#4 + + vqmovn.s16 d2, q2 ; vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * ( qs0 - ps0)) + vqmovn.s16 d3, q13 + +;;;;;;;;;;;;;; + vand q1, q1, q15 ; vp8_filter &= mask + + vld1.u8 {q15}, [r12]! ;#63 + ; + vand q13, q1, q14 ; Filter2: q13; Filter2 &= hev + + vld1.u8 {d7}, [r12]! ;#9 + ; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Change for VP8 from VP7 +; vand q2, q13, q12 ; s = Filter2 & 7 + +; vqadd.s8 q13, q13, q11 ; Filter2 = vp8_signed_char_clamp(Filter2+4) +; vld1.u8 {d6}, [r12]! ;#18 + +; sub r0, r0, r1, lsl #4 +; sub sp, sp, #32 +; add r2, r0, r1 + +; vshr.s8 q13, q13, #3 ; Filter2 >>= 3 +; vceq.i8 q2, q2, q11 ; s = (s==4)*-1 + +; add r3, r2, r1 + +; vqsub.s8 q7, q7, q13 ; qs0 = vp8_signed_char_clamp(qs0 - Filter2) +; vqadd.s8 q11, q2, q13 ; u = vp8_signed_char_clamp(s + Filter2) + +; vld1.u8 {d5}, [r12]! ;#27 +; vmov q10, q15 +; vmov q12, q15 + +; vqadd.s8 q6, q6, q11 ; ps0 = vp8_signed_char_clamp(ps0 + u) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + vqadd.s8 q2, q13, q11 ; Filter1 = vp8_signed_char_clamp(Filter2+4) + vqadd.s8 q13, q13, q12 ; Filter2 = vp8_signed_char_clamp(Filter2+3) + + vld1.u8 {d6}, [r12]! ;#18 + sub r0, r0, r1, lsl #4 + sub sp, sp, #32 + + add r2, r0, r1 + + vshr.s8 q2, q2, #3 ; Filter1 >>= 3 + vshr.s8 q13, q13, #3 ; Filter2 >>= 3 + + vmov q10, q15 + vmov q12, q15 + + vqsub.s8 q7, q7, q2 ; qs0 = vp8_signed_char_clamp(qs0 - Filter1) + + vld1.u8 {d5}, [r12]! ;#27 + add r3, r2, r1 + + vqadd.s8 q6, q6, q13 ; ps0 = vp8_signed_char_clamp(ps0 + Filter2) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + vbic q1, q1, q14 ; Filter2: q1; vp8_filter &= ~hev; Filter2 = vp8_filter + + ; roughly 1/7th difference across boundary + ; roughly 2/7th difference across boundary + ; roughly 3/7th difference across boundary + vmov q11, q15 + vmov q13, q15 + vmov q14, q15 + + vmlal.s8 q10, d2, d7 ; Filter2 * 9 + vmlal.s8 q11, d3, d7 + vmlal.s8 q12, d2, d6 ; Filter2 * 18 + vmlal.s8 q13, d3, d6 + vmlal.s8 q14, d2, d5 ; Filter2 * 27 + vmlal.s8 q15, d3, d5 + vqshrn.s16 d20, q10, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7) + vqshrn.s16 d21, q11, #7 + vqshrn.s16 d24, q12, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7) + vqshrn.s16 d25, q13, #7 + vqshrn.s16 d28, q14, #7 ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7) + vqshrn.s16 d29, q15, #7 + + vqsub.s8 q11, q9, q10 ; s = vp8_signed_char_clamp(qs2 - u) + vqadd.s8 q10, q4, q10 ; s = vp8_signed_char_clamp(ps2 + u) + vqsub.s8 q13, q8, q12 ; s = vp8_signed_char_clamp(qs1 - u) + vqadd.s8 q12, q5, q12 ; s = vp8_signed_char_clamp(ps1 + u) + vqsub.s8 q15, q7, q14 ; s = vp8_signed_char_clamp(qs0 - u) + vqadd.s8 q14, q6, q14 ; s = vp8_signed_char_clamp(ps0 + u) + veor q9, q11, q0 ; *oq2 = s^0x80 + veor q4, q10, q0 ; *op2 = s^0x80 + veor q8, q13, q0 ; *oq1 = s^0x80 + veor q5, q12, q0 ; *op2 = s^0x80 + veor q7, q15, q0 ; *oq0 = s^0x80 + vld1.u8 {q3}, [sp]! + veor q6, q14, q0 ; *op0 = s^0x80 + vld1.u8 {q10}, [sp]! + + ;transpose to 16x8 matrix + vtrn.32 q3, q7 + vtrn.32 q4, q8 + vtrn.32 q5, q9 + vtrn.32 q6, q10 + add r12, r3, r1 + + vtrn.16 q3, q5 + vtrn.16 q4, q6 + vtrn.16 q7, q9 + vtrn.16 q8, q10 + + vtrn.8 q3, q4 + vtrn.8 q5, q6 + vtrn.8 q7, q8 + vtrn.8 q9, q10 + + ;store op2, op1, op0, oq0, oq1, oq2 + vst1.8 {d6}, [r0] + vst1.8 {d8}, [r2] + vst1.8 {d10}, [r3] + vst1.8 {d12}, [r12], r1 + add r0, r12, r1 + vst1.8 {d14}, [r12] + vst1.8 {d16}, [r0], r1 + add r2, r0, r1 + vst1.8 {d18}, [r0] + vst1.8 {d20}, [r2], r1 + add r3, r2, r1 + vst1.8 {d7}, [r2] + vst1.8 {d9}, [r3], r1 + add r12, r3, r1 + vst1.8 {d11}, [r3] + vst1.8 {d13}, [r12], r1 + add r0, r12, r1 + vst1.8 {d15}, [r12] + vst1.8 {d17}, [r0], r1 + add r2, r0, r1 + vst1.8 {d19}, [r0] + vst1.8 {d21}, [r2] + + bx lr + ENDP ; |vp8_mbloop_filter_vertical_edge_y_neon| + +;----------------- + AREA mbvloopfiltery_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 16 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_mbvlfy_coeff_ + DCD mbvlfy_coeff +mbvlfy_coeff + DCD 0x80808080, 0x80808080, 0x80808080, 0x80808080 + DCD 0x03030303, 0x03030303, 0x03030303, 0x03030303 + DCD 0x04040404, 0x04040404, 0x04040404, 0x04040404 + DCD 0x003f003f, 0x003f003f, 0x003f003f, 0x003f003f + DCD 0x09090909, 0x09090909, 0x12121212, 0x12121212 + DCD 0x1b1b1b1b, 0x1b1b1b1b + + END
diff --git a/vp8/common/arm/neon/recon16x16mb_neon.asm b/vp8/common/arm/neon/recon16x16mb_neon.asm new file mode 100644 index 0000000..b9ba1cb --- /dev/null +++ b/vp8/common/arm/neon/recon16x16mb_neon.asm
@@ -0,0 +1,130 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_recon16x16mb_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *pred_ptr, +; r1 short *diff_ptr, +; r2 unsigned char *dst_ptr, +; r3 int ystride, +; stack unsigned char *udst_ptr, +; stack unsigned char *vdst_ptr + +|vp8_recon16x16mb_neon| PROC + mov r12, #4 ;loop counter for Y loop + +recon16x16mb_loop_y + vld1.u8 {q12, q13}, [r0]! ;load data from pred_ptr + vld1.16 {q8, q9}, [r1]! ;load data from diff_ptr + vld1.u8 {q14, q15}, [r0]! + vld1.16 {q10, q11}, [r1]! + + vmovl.u8 q0, d24 ;modify Pred data from 8 bits to 16 bits + vmovl.u8 q1, d25 + vmovl.u8 q2, d26 + vmovl.u8 q3, d27 + vmovl.u8 q4, d28 + vmovl.u8 q5, d29 + vmovl.u8 q6, d30 + vld1.16 {q12, q13}, [r1]! + vmovl.u8 q7, d31 + vld1.16 {q14, q15}, [r1]! + + pld [r0] + pld [r1] + pld [r1, #64] + + vadd.s16 q0, q0, q8 ;add Diff data and Pred data together + vadd.s16 q1, q1, q9 + vadd.s16 q2, q2, q10 + vadd.s16 q3, q3, q11 + vadd.s16 q4, q4, q12 + vadd.s16 q5, q5, q13 + vadd.s16 q6, q6, q14 + vadd.s16 q7, q7, q15 + + vqmovun.s16 d0, q0 ;CLAMP() saturation + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vqmovun.s16 d4, q4 + vqmovun.s16 d5, q5 + vst1.u8 {q0}, [r2], r3 ;store result + vqmovun.s16 d6, q6 + vst1.u8 {q1}, [r2], r3 + vqmovun.s16 d7, q7 + vst1.u8 {q2}, [r2], r3 + subs r12, r12, #1 + + moveq r12, #2 ;loop counter for UV loop + + vst1.u8 {q3}, [r2], r3 + bne recon16x16mb_loop_y + + mov r3, r3, lsr #1 ;uv_stride = ystride>>1 + ldr r2, [sp] ;load upred_ptr + +recon16x16mb_loop_uv + vld1.u8 {q12, q13}, [r0]! ;load data from pred_ptr + vld1.16 {q8, q9}, [r1]! ;load data from diff_ptr + vld1.u8 {q14, q15}, [r0]! + vld1.16 {q10, q11}, [r1]! + + vmovl.u8 q0, d24 ;modify Pred data from 8 bits to 16 bits + vmovl.u8 q1, d25 + vmovl.u8 q2, d26 + vmovl.u8 q3, d27 + vmovl.u8 q4, d28 + vmovl.u8 q5, d29 + vmovl.u8 q6, d30 + vld1.16 {q12, q13}, [r1]! + vmovl.u8 q7, d31 + vld1.16 {q14, q15}, [r1]! + + vadd.s16 q0, q0, q8 ;add Diff data and Pred data together + vadd.s16 q1, q1, q9 + vadd.s16 q2, q2, q10 + vadd.s16 q3, q3, q11 + vadd.s16 q4, q4, q12 + vadd.s16 q5, q5, q13 + vadd.s16 q6, q6, q14 + + vqmovun.s16 d0, q0 ;CLAMP() saturation + vadd.s16 q7, q7, q15 + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vst1.u8 {d0}, [r2], r3 ;store result + vqmovun.s16 d4, q4 + vst1.u8 {d1}, [r2], r3 + vqmovun.s16 d5, q5 + vst1.u8 {d2}, [r2], r3 + vqmovun.s16 d6, q6 + vst1.u8 {d3}, [r2], r3 + vqmovun.s16 d7, q7 + vst1.u8 {d4}, [r2], r3 + subs r12, r12, #1 + + vst1.u8 {d5}, [r2], r3 + vst1.u8 {d6}, [r2], r3 + vst1.u8 {d7}, [r2], r3 + + ldrne r2, [sp, #4] ;load vpred_ptr + bne recon16x16mb_loop_uv + + bx lr + + ENDP + END
diff --git a/vp8/common/arm/neon/recon2b_neon.asm b/vp8/common/arm/neon/recon2b_neon.asm new file mode 100644 index 0000000..25aaf8c --- /dev/null +++ b/vp8/common/arm/neon/recon2b_neon.asm
@@ -0,0 +1,53 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_recon2b_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *pred_ptr, +; r1 short *diff_ptr, +; r2 unsigned char *dst_ptr, +; r3 int stride + +|vp8_recon2b_neon| PROC + vld1.u8 {q8, q9}, [r0] ;load data from pred_ptr + vld1.16 {q4, q5}, [r1]! ;load data from diff_ptr + + vmovl.u8 q0, d16 ;modify Pred data from 8 bits to 16 bits + vld1.16 {q6, q7}, [r1]! + vmovl.u8 q1, d17 + vmovl.u8 q2, d18 + vmovl.u8 q3, d19 + + vadd.s16 q0, q0, q4 ;add Diff data and Pred data together + vadd.s16 q1, q1, q5 + vadd.s16 q2, q2, q6 + vadd.s16 q3, q3, q7 + + vqmovun.s16 d0, q0 ;CLAMP() saturation + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + add r0, r2, r3 + + vst1.u8 {d0}, [r2] ;store result + vst1.u8 {d1}, [r0], r3 + add r2, r0, r3 + vst1.u8 {d2}, [r0] + vst1.u8 {d3}, [r2], r3 + + bx lr + + ENDP + END
diff --git a/vp8/common/arm/neon/recon4b_neon.asm b/vp8/common/arm/neon/recon4b_neon.asm new file mode 100644 index 0000000..a4f5b80 --- /dev/null +++ b/vp8/common/arm/neon/recon4b_neon.asm
@@ -0,0 +1,68 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_recon4b_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *pred_ptr, +; r1 short *diff_ptr, +; r2 unsigned char *dst_ptr, +; r3 int stride + +|vp8_recon4b_neon| PROC + vld1.u8 {q12, q13}, [r0]! ;load data from pred_ptr + vld1.16 {q8, q9}, [r1]! ;load data from diff_ptr + vld1.u8 {q14, q15}, [r0] + vld1.16 {q10, q11}, [r1]! + + vmovl.u8 q0, d24 ;modify Pred data from 8 bits to 16 bits + vmovl.u8 q1, d25 + vmovl.u8 q2, d26 + vmovl.u8 q3, d27 + vmovl.u8 q4, d28 + vmovl.u8 q5, d29 + vmovl.u8 q6, d30 + vld1.16 {q12, q13}, [r1]! + vmovl.u8 q7, d31 + vld1.16 {q14, q15}, [r1] + + vadd.s16 q0, q0, q8 ;add Diff data and Pred data together + vadd.s16 q1, q1, q9 + vadd.s16 q2, q2, q10 + vadd.s16 q3, q3, q11 + vadd.s16 q4, q4, q12 + vadd.s16 q5, q5, q13 + vadd.s16 q6, q6, q14 + vadd.s16 q7, q7, q15 + + vqmovun.s16 d0, q0 ;CLAMP() saturation + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vqmovun.s16 d4, q4 + vqmovun.s16 d5, q5 + vqmovun.s16 d6, q6 + vqmovun.s16 d7, q7 + add r0, r2, r3 + + vst1.u8 {q0}, [r2] ;store result + vst1.u8 {q1}, [r0], r3 + add r2, r0, r3 + vst1.u8 {q2}, [r0] + vst1.u8 {q3}, [r2], r3 + + bx lr + + ENDP + END
diff --git a/vp8/common/arm/neon/reconb_neon.asm b/vp8/common/arm/neon/reconb_neon.asm new file mode 100644 index 0000000..16d85a0 --- /dev/null +++ b/vp8/common/arm/neon/reconb_neon.asm
@@ -0,0 +1,60 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_recon_b_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *pred_ptr, +; r1 short *diff_ptr, +; r2 unsigned char *dst_ptr, +; r3 int stride + +|vp8_recon_b_neon| PROC + mov r12, #16 + + vld1.u8 {d28}, [r0], r12 ;load 4 data/line from pred_ptr + vld1.16 {q10, q11}, [r1]! ;load data from diff_ptr + vld1.u8 {d29}, [r0], r12 + vld1.16 {q11, q12}, [r1]! + vld1.u8 {d30}, [r0], r12 + vld1.16 {q12, q13}, [r1]! + vld1.u8 {d31}, [r0], r12 + vld1.16 {q13}, [r1] + + vmovl.u8 q0, d28 ;modify Pred data from 8 bits to 16 bits + vmovl.u8 q1, d29 ;Pred data in d0, d2, d4, d6 + vmovl.u8 q2, d30 + vmovl.u8 q3, d31 + + vadd.s16 d0, d0, d20 ;add Diff data and Pred data together + vadd.s16 d2, d2, d22 + vadd.s16 d4, d4, d24 + vadd.s16 d6, d6, d26 + + vqmovun.s16 d0, q0 ;CLAMP() saturation + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + add r1, r2, r3 + + vst1.32 {d0[0]}, [r2] ;store result + vst1.32 {d1[0]}, [r1], r3 + add r2, r1, r3 + vst1.32 {d2[0]}, [r1] + vst1.32 {d3[0]}, [r2], r3 + + bx lr + + ENDP + END
diff --git a/vp8/common/arm/neon/save_neon_reg.asm b/vp8/common/arm/neon/save_neon_reg.asm new file mode 100644 index 0000000..4873e44 --- /dev/null +++ b/vp8/common/arm/neon/save_neon_reg.asm
@@ -0,0 +1,35 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_push_neon| + EXPORT |vp8_pop_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +|vp8_push_neon| PROC + vst1.i64 {d8, d9, d10, d11}, [r0]! + vst1.i64 {d12, d13, d14, d15}, [r0]! + bx lr + + ENDP + +|vp8_pop_neon| PROC + vld1.i64 {d8, d9, d10, d11}, [r0]! + vld1.i64 {d12, d13, d14, d15}, [r0]! + bx lr + + ENDP + + END +
diff --git a/vp8/common/arm/neon/shortidct4x4llm_1_neon.asm b/vp8/common/arm/neon/shortidct4x4llm_1_neon.asm new file mode 100644 index 0000000..7d06ff9 --- /dev/null +++ b/vp8/common/arm/neon/shortidct4x4llm_1_neon.asm
@@ -0,0 +1,66 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_short_idct4x4llm_1_neon| + EXPORT |vp8_dc_only_idct_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); +; r0 short *input; +; r1 short *output; +; r2 int pitch; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +|vp8_short_idct4x4llm_1_neon| PROC + vld1.16 {d0[]}, [r0] ;load input[0] + + add r3, r1, r2 + add r12, r3, r2 + + vrshr.s16 d0, d0, #3 + + add r0, r12, r2 + + vst1.16 {d0}, [r1] + vst1.16 {d0}, [r3] + vst1.16 {d0}, [r12] + vst1.16 {d0}, [r0] + + bx lr + ENDP + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;void vp8_dc_only_idct_c(short input_dc, short *output, int pitch); +; r0 short input_dc; +; r1 short *output; +; r2 int pitch; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +|vp8_dc_only_idct_neon| PROC + vdup.16 d0, r0 + + add r3, r1, r2 + add r12, r3, r2 + + vrshr.s16 d0, d0, #3 + + add r0, r12, r2 + + vst1.16 {d0}, [r1] + vst1.16 {d0}, [r3] + vst1.16 {d0}, [r12] + vst1.16 {d0}, [r0] + + bx lr + + ENDP + END
diff --git a/vp8/common/arm/neon/shortidct4x4llm_neon.asm b/vp8/common/arm/neon/shortidct4x4llm_neon.asm new file mode 100644 index 0000000..ffecfbf --- /dev/null +++ b/vp8/common/arm/neon/shortidct4x4llm_neon.asm
@@ -0,0 +1,126 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_short_idct4x4llm_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;************************************************************* +;void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) +;r0 short * input +;r1 short * output +;r2 int pitch +;************************************************************* +;static const int cospi8sqrt2minus1=20091; +;static const int sinpi8sqrt2 =35468; +;static const int rounding = 0; +;Optimization note: The resulted data from dequantization are signed 13-bit data that is +;in the range of [-4096, 4095]. This allows to use "vqdmulh"(neon) instruction since +;it won't go out of range (13+16+1=30bits<32bits). This instruction gives the high half +;result of the multiplication that is needed in IDCT. + +|vp8_short_idct4x4llm_neon| PROC + ldr r12, _idct_coeff_ + vld1.16 {q1, q2}, [r0] + vld1.16 {d0}, [r12] + + vswp d3, d4 ;q2(vp[4] vp[12]) + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + ;d6 - c1:temp1 + ;d7 - d1:temp2 + ;d8 - d1:temp1 + ;d9 - c1:temp2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vswp d3, d4 + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vrshr.s16 d2, d2, #3 + vrshr.s16 d3, d3, #3 + vrshr.s16 d4, d4, #3 + vrshr.s16 d5, d5, #3 + + add r3, r1, r2 + add r12, r3, r2 + add r0, r12, r2 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vst1.16 {d2}, [r1] + vst1.16 {d3}, [r3] + vst1.16 {d4}, [r12] + vst1.16 {d5}, [r0] + + bx lr + + ENDP + +;----------------- + AREA idct4x4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_idct_coeff_ + DCD idct_coeff +idct_coeff + DCD 0x4e7b4e7b, 0x8a8c8a8c + +;20091, 20091, 35468, 35468 + + END
diff --git a/vp8/common/arm/neon/sixtappredict16x16_neon.asm b/vp8/common/arm/neon/sixtappredict16x16_neon.asm new file mode 100644 index 0000000..9f5f0d2 --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict16x16_neon.asm
@@ -0,0 +1,494 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict16x16_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +;Note: To take advantage of 8-bit mulplication instruction in NEON. First apply abs() to +; filter coeffs to make them u8. Then, use vmlsl for negtive coeffs. After multiplication, +; the result can be negtive. So, I treat the result as s16. But, since it is also possible +; that the result can be a large positive number (> 2^15-1), which could be confused as a +; negtive number. To avoid that error, apply filter coeffs in the order of 0, 1, 4 ,5 ,2, +; which ensures that the result stays in s16 range. Finally, saturated add the result by +; applying 3rd filter coeff. Same applys to other filter functions. + +|vp8_sixtap_predict16x16_neon| PROC + push {r4-r5, lr} + + ldr r12, _filter16_coeff_ + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter16x16_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter16x16_only + + sub sp, sp, #336 ;reserve space on stack for temporary storage + mov lr, sp + + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #7 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First Pass: output_height lines x output_width columns (21x16) +filt_blk2d_fp16x16_loop_neon + vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data + vld1.u8 {d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d7, d0 + vmull.u8 q10, d9, d0 + vmull.u8 q11, d10, d0 + vmull.u8 q12, d12, d0 + vmull.u8 q13, d13, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d9, d10, #1 + vext.8 d30, d12, d13, #1 + + vmlsl.u8 q8, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q12, d30, d1 + + vext.8 d28, d7, d8, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d13, d14, #1 + + vmlsl.u8 q9, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q11, d29, d1 + vmlsl.u8 q13, d30, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d9, d10, #4 + vext.8 d30, d12, d13, #4 + + vmlsl.u8 q8, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q12, d30, d4 + + vext.8 d28, d7, d8, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d13, d14, #4 + + vmlsl.u8 q9, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q11, d29, d4 + vmlsl.u8 q13, d30, d4 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d9, d10, #5 + vext.8 d30, d12, d13, #5 + + vmlal.u8 q8, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q10, d29, d5 + vmlal.u8 q12, d30, d5 + + vext.8 d28, d7, d8, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d13, d14, #5 + + vmlal.u8 q9, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q11, d29, d5 + vmlal.u8 q13, d30, d5 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d9, d10, #2 + vext.8 d30, d12, d13, #2 + + vmlal.u8 q8, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q10, d29, d2 + vmlal.u8 q12, d30, d2 + + vext.8 d28, d7, d8, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d13, d14, #2 + + vmlal.u8 q9, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q11, d29, d2 + vmlal.u8 q13, d30, d2 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d9, d10, #3 + vext.8 d30, d12, d13, #3 + + vext.8 d15, d7, d8, #3 + vext.8 d31, d10, d11, #3 + vext.8 d6, d13, d14, #3 + + vmull.u8 q4, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + + vqadd.s16 q8, q4 ;sum of all (src_data*filter_parameters) + vqadd.s16 q10, q5 + vqadd.s16 q12, q6 + + vmull.u8 q6, d15, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q7, d31, d3 + vmull.u8 q3, d6, d3 + + subs r2, r2, #1 + + vqadd.s16 q9, q6 + vqadd.s16 q11, q7 + vqadd.s16 q13, q3 + + vqrshrun.s16 d6, q8, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q9, #7 + vqrshrun.s16 d8, q10, #7 + vqrshrun.s16 d9, q11, #7 + vqrshrun.s16 d10, q12, #7 + vqrshrun.s16 d11, q13, #7 + + vst1.u8 {d6, d7, d8}, [lr]! ;store result + vst1.u8 {d9, d10, d11}, [lr]! + + bne filt_blk2d_fp16x16_loop_neon + +;Second pass: 16x16 +;secondpass_filter - do first 8-columns and then second 8-columns + add r3, r12, r3, lsl #5 + sub lr, lr, #336 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + mov r3, #2 ;loop counter + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + mov r2, #16 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_sp16x16_outloop_neon + vld1.u8 {d18}, [lr], r2 ;load src data + vld1.u8 {d19}, [lr], r2 + vld1.u8 {d20}, [lr], r2 + vld1.u8 {d21}, [lr], r2 + mov r12, #4 ;loop counter + vld1.u8 {d22}, [lr], r2 + +secondpass_inner_loop_neon + vld1.u8 {d23}, [lr], r2 ;load src data + vld1.u8 {d24}, [lr], r2 + vld1.u8 {d25}, [lr], r2 + vld1.u8 {d26}, [lr], r2 + + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r12, r12, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vmov q9, q11 + vst1.u8 {d7}, [r4], r5 + vmov q10, q12 + vst1.u8 {d8}, [r4], r5 + vmov d22, d26 + vst1.u8 {d9}, [r4], r5 + + bne secondpass_inner_loop_neon + + subs r3, r3, #1 + sub lr, lr, #336 + add lr, lr, #8 + + sub r4, r4, r5, lsl #4 + add r4, r4, #8 + + bne filt_blk2d_sp16x16_outloop_neon + + add sp, sp, #336 + pop {r4-r5,pc} + +;-------------------- +firstpass_filter16x16_only + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #8 ;loop counter + sub r0, r0, #2 ;move srcptr back to (column-2) + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First Pass: output_height lines x output_width columns (16x16) +filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d6, d7, d8}, [r0], r1 ;load src data + vld1.u8 {d9, d10, d11}, [r0], r1 + + pld [r0] + pld [r0, r1] + + vmull.u8 q6, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q7, d7, d0 + vmull.u8 q8, d9, d0 + vmull.u8 q9, d10, d0 + + vext.8 d20, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d21, d9, d10, #1 + vext.8 d22, d7, d8, #1 + vext.8 d23, d10, d11, #1 + vext.8 d24, d6, d7, #4 ;construct src_ptr[2] + vext.8 d25, d9, d10, #4 + vext.8 d26, d7, d8, #4 + vext.8 d27, d10, d11, #4 + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d9, d10, #5 + + vmlsl.u8 q6, d20, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d21, d1 + vmlsl.u8 q7, d22, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d23, d1 + vmlsl.u8 q6, d24, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d25, d4 + vmlsl.u8 q7, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d27, d4 + vmlal.u8 q6, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + + vext.8 d20, d7, d8, #5 + vext.8 d21, d10, d11, #5 + vext.8 d22, d6, d7, #2 ;construct src_ptr[0] + vext.8 d23, d9, d10, #2 + vext.8 d24, d7, d8, #2 + vext.8 d25, d10, d11, #2 + + vext.8 d26, d6, d7, #3 ;construct src_ptr[1] + vext.8 d27, d9, d10, #3 + vext.8 d28, d7, d8, #3 + vext.8 d29, d10, d11, #3 + + vmlal.u8 q7, d20, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d21, d5 + vmlal.u8 q6, d22, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d23, d2 + vmlal.u8 q7, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d25, d2 + + vmull.u8 q10, d26, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q11, d27, d3 + vmull.u8 q12, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q15, d29, d3 + + vqadd.s16 q6, q10 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q11 + vqadd.s16 q7, q12 + vqadd.s16 q9, q15 + + subs r2, r2, #1 + + vqrshrun.s16 d6, q6, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q7, #7 + vqrshrun.s16 d8, q8, #7 + vqrshrun.s16 d9, q9, #7 + + vst1.u8 {q3}, [r4], r5 ;store result + vst1.u8 {q4}, [r4], r5 + + bne filt_blk2d_fpo16x16_loop_neon + + pop {r4-r5,pc} + +;-------------------- +secondpass_filter16x16_only +;Second pass: 16x16 + add r3, r12, r3, lsl #5 + sub r0, r0, r1, lsl #1 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + mov r3, #2 ;loop counter + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_spo16x16_outloop_neon + vld1.u8 {d18}, [r0], r1 ;load src data + vld1.u8 {d19}, [r0], r1 + vld1.u8 {d20}, [r0], r1 + vld1.u8 {d21}, [r0], r1 + mov r12, #4 ;loop counter + vld1.u8 {d22}, [r0], r1 + +secondpass_only_inner_loop_neon + vld1.u8 {d23}, [r0], r1 ;load src data + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r12, r12, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vmov q9, q11 + vst1.u8 {d7}, [r4], r5 + vmov q10, q12 + vst1.u8 {d8}, [r4], r5 + vmov d22, d26 + vst1.u8 {d9}, [r4], r5 + + bne secondpass_only_inner_loop_neon + + subs r3, r3, #1 + sub r0, r0, r1, lsl #4 + sub r0, r0, r1, lsl #2 + sub r0, r0, r1 + add r0, r0, #8 + + sub r4, r4, r5, lsl #4 + add r4, r4, #8 + + bne filt_blk2d_spo16x16_outloop_neon + + pop {r4-r5,pc} + + ENDP + +;----------------- + AREA subpelfilters16_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_filter16_coeff_ + DCD filter16_coeff +filter16_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + + END
diff --git a/vp8/common/arm/neon/sixtappredict4x4_neon.asm b/vp8/common/arm/neon/sixtappredict4x4_neon.asm new file mode 100644 index 0000000..c23a9db --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict4x4_neon.asm
@@ -0,0 +1,425 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(lr) int dst_pitch + +|vp8_sixtap_predict_neon| PROC + push {r4, lr} + + ldr r12, _filter4_coeff_ + ldr r4, [sp, #8] ;load parameters from stack + ldr lr, [sp, #12] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter4x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter4x4_only + + vabs.s32 q12, q14 ;get abs(filer_parameters) + vabs.s32 q13, q15 + + sub r0, r0, #2 ;go back 2 columns of src data + sub r0, r0, r1, lsl #1 ;go back 2 lines of src data + +;First pass: output_height lines x output_width columns (9x4) + vld1.u8 {q3}, [r0], r1 ;load first 4-line src data + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + + vld1.u8 {q3}, [r0], r1 ;load rest 5-line src data + vld1.u8 {q4}, [r0], r1 + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + + vld1.u8 {q5}, [r0], r1 + vld1.u8 {q6}, [r0], r1 + + vqrshrun.s16 d27, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d28, q8, #7 + + ;First Pass on rest 5-line data + vld1.u8 {q11}, [r0], r1 + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vext.8 d31, d22, d23, #5 ;construct src_ptr[3] + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + vmull.u8 q12, d31, d5 ;(src_ptr[3] * vp8_filter[5]) + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + vmlal.u8 q12, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vext.8 d31, d22, d23, #1 ;construct src_ptr[-1] + + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + vmlsl.u8 q12, d31, d1 ;-(src_ptr[-1] * vp8_filter[1]) + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vext.8 d31, d22, d23, #4 ;construct src_ptr[2] + + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + vmlsl.u8 q12, d31, d4 ;-(src_ptr[2] * vp8_filter[4]) + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vext.8 d31, d22, d23, #2 ;construct src_ptr[0] + + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + vmlal.u8 q12, d31, d2 ;(src_ptr[0] * vp8_filter[2]) + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vext.8 d31, d22, d23, #3 ;construct src_ptr[1] + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + vmull.u8 q11, d31, d3 ;(src_ptr[1] * vp8_filter[3]) + + add r3, r12, r3, lsl #5 + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + vqadd.s16 q12, q11 + + vext.8 d23, d27, d28, #4 + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + + vqrshrun.s16 d29, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d30, q8, #7 + vqrshrun.s16 d31, q12, #7 + +;Second pass: 4x4 + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vext.8 d24, d28, d29, #4 + vext.8 d25, d29, d30, #4 + vext.8 d26, d30, d31, #4 + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + + vmull.u8 q3, d27, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d28, d0 + + vmull.u8 q5, d25, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q6, d26, d5 + + vmlsl.u8 q3, d29, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d30, d4 + + vmlsl.u8 q5, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q6, d24, d1 + + vmlal.u8 q3, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d29, d2 + + vmlal.u8 q5, d24, d3 ;(src_ptr[1] * vp8_filter[3]) + vmlal.u8 q6, d25, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q5, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q6, q4 + + vqrshrun.s16 d3, q5, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d4, q6, #7 + + vst1.32 {d3[0]}, [r4] ;store result + vst1.32 {d3[1]}, [r0] + vst1.32 {d4[0]}, [r1] + vst1.32 {d4[1]}, [r2] + + pop {r4, pc} + + +;--------------------- +firstpass_filter4x4_only + vabs.s32 q12, q14 ;get abs(filer_parameters) + vabs.s32 q13, q15 + + sub r0, r0, #2 ;go back 2 columns of src data + +;First pass: output_height lines x output_width columns (4x4) + vld1.u8 {q3}, [r0], r1 ;load first 4-line src data + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + + vext.8 d18, d6, d7, #5 ;construct src_ptr[3] + vext.8 d19, d8, d9, #5 + vext.8 d20, d10, d11, #5 + vext.8 d21, d12, d13, #5 + + vswp d7, d8 ;discard 2nd half data after src_ptr[3] is done + vswp d11, d12 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[3]) + vzip.32 d20, d21 + vmull.u8 q7, d18, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q8, d20, d5 + + vmov q4, q3 ;keep original src data in q4 q6 + vmov q6, q5 + + vzip.32 d6, d7 ;construct src_ptr[-2], and put 2-line data together + vzip.32 d10, d11 + vshr.u64 q9, q4, #8 ;construct src_ptr[-1] + vshr.u64 q10, q6, #8 + vmlal.u8 q7, d6, d0 ;+(src_ptr[-2] * vp8_filter[0]) + vmlal.u8 q8, d10, d0 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[-1]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #32 ;construct src_ptr[2] + vshr.u64 q5, q6, #32 + vmlsl.u8 q7, d18, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d20, d1 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[2]) + vzip.32 d10, d11 + vshr.u64 q9, q4, #16 ;construct src_ptr[0] + vshr.u64 q10, q6, #16 + vmlsl.u8 q7, d6, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d10, d4 + + vzip.32 d18, d19 ;put 2-line data in 1 register (src_ptr[0]) + vzip.32 d20, d21 + vshr.u64 q3, q4, #24 ;construct src_ptr[1] + vshr.u64 q5, q6, #24 + vmlal.u8 q7, d18, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d20, d2 + + vzip.32 d6, d7 ;put 2-line data in 1 register (src_ptr[1]) + vzip.32 d10, d11 + vmull.u8 q9, d6, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q10, d10, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q7, q9 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q10 + + vqrshrun.s16 d27, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d28, q8, #7 + + vst1.32 {d27[0]}, [r4] ;store result + vst1.32 {d27[1]}, [r0] + vst1.32 {d28[0]}, [r1] + vst1.32 {d28[1]}, [r2] + + pop {r4, pc} + + +;--------------------- +secondpass_filter4x4_only + sub r0, r0, r1, lsl #1 + add r3, r12, r3, lsl #5 + + vld1.32 {d27[0]}, [r0], r1 ;load src data + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.32 {d27[1]}, [r0], r1 + vabs.s32 q7, q5 + vld1.32 {d28[0]}, [r0], r1 + vabs.s32 q8, q6 + vld1.32 {d28[1]}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.32 {d29[0]}, [r0], r1 + vdup.8 d1, d14[4] + vld1.32 {d29[1]}, [r0], r1 + vdup.8 d2, d15[0] + vld1.32 {d30[0]}, [r0], r1 + vdup.8 d3, d15[4] + vld1.32 {d30[1]}, [r0], r1 + vdup.8 d4, d16[0] + vld1.32 {d31[0]}, [r0], r1 + vdup.8 d5, d16[4] + + vext.8 d23, d27, d28, #4 + vext.8 d24, d28, d29, #4 + vext.8 d25, d29, d30, #4 + vext.8 d26, d30, d31, #4 + + vmull.u8 q3, d27, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d28, d0 + + vmull.u8 q5, d25, d5 ;(src_ptr[3] * vp8_filter[5]) + vmull.u8 q6, d26, d5 + + vmlsl.u8 q3, d29, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d30, d4 + + vmlsl.u8 q5, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q6, d24, d1 + + vmlal.u8 q3, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d29, d2 + + vmlal.u8 q5, d24, d3 ;(src_ptr[1] * vp8_filter[3]) + vmlal.u8 q6, d25, d3 + + add r0, r4, lr + add r1, r0, lr + add r2, r1, lr + + vqadd.s16 q5, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q6, q4 + + vqrshrun.s16 d3, q5, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d4, q6, #7 + + vst1.32 {d3[0]}, [r4] ;store result + vst1.32 {d3[1]}, [r0] + vst1.32 {d4[0]}, [r1] + vst1.32 {d4[1]}, [r2] + + pop {r4, pc} + + ENDP + +;----------------- + AREA subpelfilters4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_filter4_coeff_ + DCD filter4_coeff +filter4_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + + END
diff --git a/vp8/common/arm/neon/sixtappredict8x4_neon.asm b/vp8/common/arm/neon/sixtappredict8x4_neon.asm new file mode 100644 index 0000000..18e19f9 --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict8x4_neon.asm
@@ -0,0 +1,476 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; r4 unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_sixtap_predict8x4_neon| PROC + push {r4-r5, lr} + + ldr r12, _filter8_coeff_ + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x4_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter8x4_only + + sub sp, sp, #32 ;reserve space on stack for temporary storage + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + mov lr, sp + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + +;First pass: output_height lines x output_width columns (9x8) + vld1.u8 {q3}, [r0], r1 ;load src data + vdup.8 d3, d25[4] + vld1.u8 {q4}, [r0], r1 + vdup.8 d4, d26[0] + vld1.u8 {q5}, [r0], r1 + vdup.8 d5, d26[4] + vld1.u8 {q6}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vld1.u8 {q3}, [r0], r1 ;load src data + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vld1.u8 {q4}, [r0], r1 + vst1.u8 {d22}, [lr]! ;store result + vld1.u8 {q5}, [r0], r1 + vst1.u8 {d23}, [lr]! + vld1.u8 {q6}, [r0], r1 + vst1.u8 {d24}, [lr]! + vld1.u8 {q7}, [r0], r1 + vst1.u8 {d25}, [lr]! + + ;first_pass filtering on the rest 5-line data + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + vmull.u8 q11, d12, d0 + vmull.u8 q12, d14, d0 + + vext.8 d27, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d28, d8, d9, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d12, d13, #1 + vext.8 d31, d14, d15, #1 + + vmlsl.u8 q8, d27, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d28, d1 + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q11, d30, d1 + vmlsl.u8 q12, d31, d1 + + vext.8 d27, d6, d7, #4 ;construct src_ptr[2] + vext.8 d28, d8, d9, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d12, d13, #4 + vext.8 d31, d14, d15, #4 + + vmlsl.u8 q8, d27, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d28, d4 + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q11, d30, d4 + vmlsl.u8 q12, d31, d4 + + vext.8 d27, d6, d7, #2 ;construct src_ptr[0] + vext.8 d28, d8, d9, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d12, d13, #2 + vext.8 d31, d14, d15, #2 + + vmlal.u8 q8, d27, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d28, d2 + vmlal.u8 q10, d29, d2 + vmlal.u8 q11, d30, d2 + vmlal.u8 q12, d31, d2 + + vext.8 d27, d6, d7, #5 ;construct src_ptr[3] + vext.8 d28, d8, d9, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d12, d13, #5 + vext.8 d31, d14, d15, #5 + + vmlal.u8 q8, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d28, d5 + vmlal.u8 q10, d29, d5 + vmlal.u8 q11, d30, d5 + vmlal.u8 q12, d31, d5 + + vext.8 d27, d6, d7, #3 ;construct src_ptr[1] + vext.8 d28, d8, d9, #3 + vext.8 d29, d10, d11, #3 + vext.8 d30, d12, d13, #3 + vext.8 d31, d14, d15, #3 + + vmull.u8 q3, d27, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d28, d3 + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + vmull.u8 q7, d31, d3 + + vqadd.s16 q8, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q9, q4 + vqadd.s16 q10, q5 + vqadd.s16 q11, q6 + vqadd.s16 q12, q7 + + vqrshrun.s16 d26, q8, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d27, q9, #7 + vqrshrun.s16 d28, q10, #7 + vqrshrun.s16 d29, q11, #7 ;load intermediate data from stack + vqrshrun.s16 d30, q12, #7 + +;Second pass: 8x4 +;secondpass_filter + add r3, r12, r3, lsl #5 + sub lr, lr, #32 + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.u8 {q11}, [lr]! + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vld1.u8 {q12}, [lr]! + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + + vmull.u8 q3, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d23, d0 + vmull.u8 q5, d24, d0 + vmull.u8 q6, d25, d0 + + vmlsl.u8 q3, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d24, d1 + vmlsl.u8 q5, d25, d1 + vmlsl.u8 q6, d26, d1 + + vmlsl.u8 q3, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d27, d4 + vmlsl.u8 q5, d28, d4 + vmlsl.u8 q6, d29, d4 + + vmlal.u8 q3, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d25, d2 + vmlal.u8 q5, d26, d2 + vmlal.u8 q6, d27, d2 + + vmlal.u8 q3, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d28, d5 + vmlal.u8 q5, d29, d5 + vmlal.u8 q6, d30, d5 + + vmull.u8 q7, d25, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d26, d3 + vmull.u8 q9, d27, d3 + vmull.u8 q10, d28, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vst1.u8 {d7}, [r4], r5 + vst1.u8 {d8}, [r4], r5 + vst1.u8 {d9}, [r4], r5 + + add sp, sp, #32 + pop {r4-r5,pc} + +;-------------------- +firstpass_filter8x4_only + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + vld1.u8 {q3}, [r0], r1 ;load src data + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vld1.u8 {q4}, [r0], r1 + vdup.8 d1, d24[4] + vld1.u8 {q5}, [r0], r1 + vdup.8 d2, d25[0] + vld1.u8 {q6}, [r0], r1 + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First pass: output_height lines x output_width columns (4x8) + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [r4], r5 ;store result + vst1.u8 {d23}, [r4], r5 + vst1.u8 {d24}, [r4], r5 + vst1.u8 {d25}, [r4], r5 + + pop {r4-r5,pc} + +;--------------------- +secondpass_filter8x4_only +;Second pass: 8x4 + add r3, r12, r3, lsl #5 + sub r0, r0, r1, lsl #1 + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vld1.u8 {d22}, [r0], r1 + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.u8 {d25}, [r0], r1 + vdup.8 d1, d14[4] + vld1.u8 {d26}, [r0], r1 + vdup.8 d2, d15[0] + vld1.u8 {d27}, [r0], r1 + vdup.8 d3, d15[4] + vld1.u8 {d28}, [r0], r1 + vdup.8 d4, d16[0] + vld1.u8 {d29}, [r0], r1 + vdup.8 d5, d16[4] + vld1.u8 {d30}, [r0], r1 + + vmull.u8 q3, d22, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d23, d0 + vmull.u8 q5, d24, d0 + vmull.u8 q6, d25, d0 + + vmlsl.u8 q3, d23, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d24, d1 + vmlsl.u8 q5, d25, d1 + vmlsl.u8 q6, d26, d1 + + vmlsl.u8 q3, d26, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d27, d4 + vmlsl.u8 q5, d28, d4 + vmlsl.u8 q6, d29, d4 + + vmlal.u8 q3, d24, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d25, d2 + vmlal.u8 q5, d26, d2 + vmlal.u8 q6, d27, d2 + + vmlal.u8 q3, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d28, d5 + vmlal.u8 q5, d29, d5 + vmlal.u8 q6, d30, d5 + + vmull.u8 q7, d25, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d26, d3 + vmull.u8 q9, d27, d3 + vmull.u8 q10, d28, d3 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vst1.u8 {d6}, [r4], r5 ;store result + vst1.u8 {d7}, [r4], r5 + vst1.u8 {d8}, [r4], r5 + vst1.u8 {d9}, [r4], r5 + + pop {r4-r5,pc} + + ENDP + +;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_filter8_coeff_ + DCD filter8_coeff +filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + + END
diff --git a/vp8/common/arm/neon/sixtappredict8x8_neon.asm b/vp8/common/arm/neon/sixtappredict8x8_neon.asm new file mode 100644 index 0000000..d27485e --- /dev/null +++ b/vp8/common/arm/neon/sixtappredict8x8_neon.asm
@@ -0,0 +1,527 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sixtap_predict8x8_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(r5) int dst_pitch + +|vp8_sixtap_predict8x8_neon| PROC + push {r4-r5, lr} + + ldr r12, _filter8_coeff_ + + ldr r4, [sp, #12] ;load parameters from stack + ldr r5, [sp, #16] ;load parameters from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_filter8x8_only + + add r2, r12, r2, lsl #5 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {q14, q15}, [r2] ;load first_pass filter + + beq firstpass_filter8x8_only + + sub sp, sp, #64 ;reserve space on stack for temporary storage + mov lr, sp + + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #2 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + sub r0, r0, r1, lsl #1 + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + +;First pass: output_height lines x output_width columns (13x8) + vld1.u8 {q3}, [r0], r1 ;load src data + vdup.8 d3, d25[4] + vld1.u8 {q4}, [r0], r1 + vdup.8 d4, d26[0] + vld1.u8 {q5}, [r0], r1 + vdup.8 d5, d26[4] + vld1.u8 {q6}, [r0], r1 + +filt_blk2d_fp8x8_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + + subs r2, r2, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vld1.u8 {q3}, [r0], r1 ;load src data + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [lr]! ;store result + vld1.u8 {q4}, [r0], r1 + vst1.u8 {d23}, [lr]! + vld1.u8 {q5}, [r0], r1 + vst1.u8 {d24}, [lr]! + vld1.u8 {q6}, [r0], r1 + vst1.u8 {d25}, [lr]! + + bne filt_blk2d_fp8x8_loop_neon + + ;first_pass filtering on the rest 5-line data + ;vld1.u8 {q3}, [r0], r1 ;load src data + ;vld1.u8 {q4}, [r0], r1 + ;vld1.u8 {q5}, [r0], r1 + ;vld1.u8 {q6}, [r0], r1 + vld1.u8 {q7}, [r0], r1 + + vmull.u8 q8, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + vmull.u8 q11, d12, d0 + vmull.u8 q12, d14, d0 + + vext.8 d27, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d28, d8, d9, #1 + vext.8 d29, d10, d11, #1 + vext.8 d30, d12, d13, #1 + vext.8 d31, d14, d15, #1 + + vmlsl.u8 q8, d27, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q9, d28, d1 + vmlsl.u8 q10, d29, d1 + vmlsl.u8 q11, d30, d1 + vmlsl.u8 q12, d31, d1 + + vext.8 d27, d6, d7, #4 ;construct src_ptr[2] + vext.8 d28, d8, d9, #4 + vext.8 d29, d10, d11, #4 + vext.8 d30, d12, d13, #4 + vext.8 d31, d14, d15, #4 + + vmlsl.u8 q8, d27, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q9, d28, d4 + vmlsl.u8 q10, d29, d4 + vmlsl.u8 q11, d30, d4 + vmlsl.u8 q12, d31, d4 + + vext.8 d27, d6, d7, #2 ;construct src_ptr[0] + vext.8 d28, d8, d9, #2 + vext.8 d29, d10, d11, #2 + vext.8 d30, d12, d13, #2 + vext.8 d31, d14, d15, #2 + + vmlal.u8 q8, d27, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q9, d28, d2 + vmlal.u8 q10, d29, d2 + vmlal.u8 q11, d30, d2 + vmlal.u8 q12, d31, d2 + + vext.8 d27, d6, d7, #5 ;construct src_ptr[3] + vext.8 d28, d8, d9, #5 + vext.8 d29, d10, d11, #5 + vext.8 d30, d12, d13, #5 + vext.8 d31, d14, d15, #5 + + vmlal.u8 q8, d27, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q9, d28, d5 + vmlal.u8 q10, d29, d5 + vmlal.u8 q11, d30, d5 + vmlal.u8 q12, d31, d5 + + vext.8 d27, d6, d7, #3 ;construct src_ptr[1] + vext.8 d28, d8, d9, #3 + vext.8 d29, d10, d11, #3 + vext.8 d30, d12, d13, #3 + vext.8 d31, d14, d15, #3 + + vmull.u8 q3, d27, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d28, d3 + vmull.u8 q5, d29, d3 + vmull.u8 q6, d30, d3 + vmull.u8 q7, d31, d3 + + vqadd.s16 q8, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q9, q4 + vqadd.s16 q10, q5 + vqadd.s16 q11, q6 + vqadd.s16 q12, q7 + + add r3, r12, r3, lsl #5 + + vqrshrun.s16 d26, q8, #7 ;shift/round/saturate to u8 + sub lr, lr, #64 + vqrshrun.s16 d27, q9, #7 + vld1.u8 {q9}, [lr]! ;load intermediate data from stack + vqrshrun.s16 d28, q10, #7 + vld1.u8 {q10}, [lr]! + + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + + vqrshrun.s16 d29, q11, #7 + vld1.u8 {q11}, [lr]! + + vabs.s32 q7, q5 + vabs.s32 q8, q6 + + vqrshrun.s16 d30, q12, #7 + vld1.u8 {q12}, [lr]! + +;Second pass: 8x8 + mov r3, #2 ;loop counter + + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vdup.8 d1, d14[4] + vdup.8 d2, d15[0] + vdup.8 d3, d15[4] + vdup.8 d4, d16[0] + vdup.8 d5, d16[4] + +filt_blk2d_sp8x8_loop_neon + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r3, r3, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vmov q9, q11 + vst1.u8 {d6}, [r4], r5 ;store result + vmov q10, q12 + vst1.u8 {d7}, [r4], r5 + vmov q11, q13 + vst1.u8 {d8}, [r4], r5 + vmov q12, q14 + vst1.u8 {d9}, [r4], r5 + vmov d26, d30 + + bne filt_blk2d_sp8x8_loop_neon + + add sp, sp, #64 + pop {r4-r5,pc} + +;--------------------- +firstpass_filter8x8_only + ;add r2, r12, r2, lsl #5 ;calculate filter location + ;vld1.s32 {q14, q15}, [r2] ;load first_pass filter + vabs.s32 q12, q14 + vabs.s32 q13, q15 + + mov r2, #2 ;loop counter + sub r0, r0, #2 ;move srcptr back to (line-2) and (column-2) + + vdup.8 d0, d24[0] ;first_pass filter (d0-d5) + vdup.8 d1, d24[4] + vdup.8 d2, d25[0] + vdup.8 d3, d25[4] + vdup.8 d4, d26[0] + vdup.8 d5, d26[4] + +;First pass: output_height lines x output_width columns (8x8) +filt_blk2d_fpo8x8_loop_neon + vld1.u8 {q3}, [r0], r1 ;load src data + vld1.u8 {q4}, [r0], r1 + vld1.u8 {q5}, [r0], r1 + vld1.u8 {q6}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d6, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q8, d8, d0 + vmull.u8 q9, d10, d0 + vmull.u8 q10, d12, d0 + + vext.8 d28, d6, d7, #1 ;construct src_ptr[-1] + vext.8 d29, d8, d9, #1 + vext.8 d30, d10, d11, #1 + vext.8 d31, d12, d13, #1 + + vmlsl.u8 q7, d28, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q8, d29, d1 + vmlsl.u8 q9, d30, d1 + vmlsl.u8 q10, d31, d1 + + vext.8 d28, d6, d7, #4 ;construct src_ptr[2] + vext.8 d29, d8, d9, #4 + vext.8 d30, d10, d11, #4 + vext.8 d31, d12, d13, #4 + + vmlsl.u8 q7, d28, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q8, d29, d4 + vmlsl.u8 q9, d30, d4 + vmlsl.u8 q10, d31, d4 + + vext.8 d28, d6, d7, #2 ;construct src_ptr[0] + vext.8 d29, d8, d9, #2 + vext.8 d30, d10, d11, #2 + vext.8 d31, d12, d13, #2 + + vmlal.u8 q7, d28, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q8, d29, d2 + vmlal.u8 q9, d30, d2 + vmlal.u8 q10, d31, d2 + + vext.8 d28, d6, d7, #5 ;construct src_ptr[3] + vext.8 d29, d8, d9, #5 + vext.8 d30, d10, d11, #5 + vext.8 d31, d12, d13, #5 + + vmlal.u8 q7, d28, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q8, d29, d5 + vmlal.u8 q9, d30, d5 + vmlal.u8 q10, d31, d5 + + vext.8 d28, d6, d7, #3 ;construct src_ptr[1] + vext.8 d29, d8, d9, #3 + vext.8 d30, d10, d11, #3 + vext.8 d31, d12, d13, #3 + + vmull.u8 q3, d28, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q4, d29, d3 + vmull.u8 q5, d30, d3 + vmull.u8 q6, d31, d3 + ; + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + subs r2, r2, #1 + + vqrshrun.s16 d22, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d23, q8, #7 + vqrshrun.s16 d24, q9, #7 + vqrshrun.s16 d25, q10, #7 + + vst1.u8 {d22}, [r4], r5 ;store result + vst1.u8 {d23}, [r4], r5 + vst1.u8 {d24}, [r4], r5 + vst1.u8 {d25}, [r4], r5 + + bne filt_blk2d_fpo8x8_loop_neon + + pop {r4-r5,pc} + +;--------------------- +secondpass_filter8x8_only + sub r0, r0, r1, lsl #1 + add r3, r12, r3, lsl #5 + + vld1.u8 {d18}, [r0], r1 ;load src data + vld1.s32 {q5, q6}, [r3] ;load second_pass filter + vld1.u8 {d19}, [r0], r1 + vabs.s32 q7, q5 + vld1.u8 {d20}, [r0], r1 + vabs.s32 q8, q6 + vld1.u8 {d21}, [r0], r1 + mov r3, #2 ;loop counter + vld1.u8 {d22}, [r0], r1 + vdup.8 d0, d14[0] ;second_pass filter parameters (d0-d5) + vld1.u8 {d23}, [r0], r1 + vdup.8 d1, d14[4] + vld1.u8 {d24}, [r0], r1 + vdup.8 d2, d15[0] + vld1.u8 {d25}, [r0], r1 + vdup.8 d3, d15[4] + vld1.u8 {d26}, [r0], r1 + vdup.8 d4, d16[0] + vld1.u8 {d27}, [r0], r1 + vdup.8 d5, d16[4] + vld1.u8 {d28}, [r0], r1 + vld1.u8 {d29}, [r0], r1 + vld1.u8 {d30}, [r0], r1 + +;Second pass: 8x8 +filt_blk2d_spo8x8_loop_neon + vmull.u8 q3, d18, d0 ;(src_ptr[-2] * vp8_filter[0]) + vmull.u8 q4, d19, d0 + vmull.u8 q5, d20, d0 + vmull.u8 q6, d21, d0 + + vmlsl.u8 q3, d19, d1 ;-(src_ptr[-1] * vp8_filter[1]) + vmlsl.u8 q4, d20, d1 + vmlsl.u8 q5, d21, d1 + vmlsl.u8 q6, d22, d1 + + vmlsl.u8 q3, d22, d4 ;-(src_ptr[2] * vp8_filter[4]) + vmlsl.u8 q4, d23, d4 + vmlsl.u8 q5, d24, d4 + vmlsl.u8 q6, d25, d4 + + vmlal.u8 q3, d20, d2 ;(src_ptr[0] * vp8_filter[2]) + vmlal.u8 q4, d21, d2 + vmlal.u8 q5, d22, d2 + vmlal.u8 q6, d23, d2 + + vmlal.u8 q3, d23, d5 ;(src_ptr[3] * vp8_filter[5]) + vmlal.u8 q4, d24, d5 + vmlal.u8 q5, d25, d5 + vmlal.u8 q6, d26, d5 + + vmull.u8 q7, d21, d3 ;(src_ptr[1] * vp8_filter[3]) + vmull.u8 q8, d22, d3 + vmull.u8 q9, d23, d3 + vmull.u8 q10, d24, d3 + + subs r3, r3, #1 + + vqadd.s16 q7, q3 ;sum of all (src_data*filter_parameters) + vqadd.s16 q8, q4 + vqadd.s16 q9, q5 + vqadd.s16 q10, q6 + + vqrshrun.s16 d6, q7, #7 ;shift/round/saturate to u8 + vqrshrun.s16 d7, q8, #7 + vqrshrun.s16 d8, q9, #7 + vqrshrun.s16 d9, q10, #7 + + vmov q9, q11 + vst1.u8 {d6}, [r4], r5 ;store result + vmov q10, q12 + vst1.u8 {d7}, [r4], r5 + vmov q11, q13 + vst1.u8 {d8}, [r4], r5 + vmov q12, q14 + vst1.u8 {d9}, [r4], r5 + vmov d26, d30 + + bne filt_blk2d_spo8x8_loop_neon + + pop {r4-r5,pc} + + ENDP + +;----------------- + AREA subpelfilters8_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_filter8_coeff_ + DCD filter8_coeff +filter8_coeff + DCD 0, 0, 128, 0, 0, 0, 0, 0 + DCD 0, -6, 123, 12, -1, 0, 0, 0 + DCD 2, -11, 108, 36, -8, 1, 0, 0 + DCD 0, -9, 93, 50, -6, 0, 0, 0 + DCD 3, -16, 77, 77, -16, 3, 0, 0 + DCD 0, -6, 50, 93, -9, 0, 0, 0 + DCD 1, -8, 36, 108, -11, 2, 0, 0 + DCD 0, -1, 12, 123, -6, 0, 0, 0 + + END
diff --git a/vp8/common/arm/recon_arm.c b/vp8/common/arm/recon_arm.c new file mode 100644 index 0000000..130059e --- /dev/null +++ b/vp8/common/arm/recon_arm.c
@@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "blockd.h" + +extern void vp8_recon16x16mb_neon(unsigned char *pred_ptr, short *diff_ptr, unsigned char *dst_ptr, int ystride, unsigned char *udst_ptr, unsigned char *vdst_ptr); + +/* +void vp8_recon16x16mby(MACROBLOCKD *x) +{ + int i; + for(i=0;i<16;i+=4) + { + //vp8_recon4b(&x->block[i]); + BLOCKD *b = &x->block[i]; + vp8_recon4b (b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } +} +*/ +void vp8_recon16x16mby(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + BLOCKD *b = &x->block[0]; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + + //b = &x->block[4]; + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + + //b = &x->block[8]; + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + + //b = &x->block[12]; + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); +} + +#if HAVE_ARMV7 +void vp8_recon16x16mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + unsigned char *pred_ptr = &x->predictor[0]; + short *diff_ptr = &x->diff[0]; + unsigned char *dst_ptr = x->dst.y_buffer; + unsigned char *udst_ptr = x->dst.u_buffer; + unsigned char *vdst_ptr = x->dst.v_buffer; + int ystride = x->dst.y_stride; + //int uv_stride = x->dst.uv_stride; + + vp8_recon16x16mb_neon(pred_ptr, diff_ptr, dst_ptr, ystride, udst_ptr, vdst_ptr); +} + +#else +/* +void vp8_recon16x16mb(MACROBLOCKD *x) +{ + int i; + + for(i=0;i<16;i+=4) + { +// vp8_recon4b(&x->block[i]); + BLOCKD *b = &x->block[i]; + vp8_recon4b (b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + + } + for(i=16;i<24;i+=2) + { +// vp8_recon2b(&x->block[i]); + BLOCKD *b = &x->block[i]; + vp8_recon2b (b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } +} +*/ +void vp8_recon16x16mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + BLOCKD *b = &x->block[0]; + + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 4; + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 4; + + //b = &x->block[16]; + + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b++; + b++; + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b++; + b++; + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b++; + b++; + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); +} +#endif
diff --git a/vp8/common/arm/recon_arm.h b/vp8/common/arm/recon_arm.h new file mode 100644 index 0000000..fd9f85e --- /dev/null +++ b/vp8/common/arm/recon_arm.h
@@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef RECON_ARM_H +#define RECON_ARM_H + +#if HAVE_ARMV6 +extern prototype_recon_block(vp8_recon_b_armv6); +extern prototype_recon_block(vp8_recon2b_armv6); +extern prototype_recon_block(vp8_recon4b_armv6); + +extern prototype_copy_block(vp8_copy_mem8x8_v6); +extern prototype_copy_block(vp8_copy_mem8x4_v6); +extern prototype_copy_block(vp8_copy_mem16x16_v6); + +#undef vp8_recon_recon +#define vp8_recon_recon vp8_recon_b_armv6 + +#undef vp8_recon_recon2 +#define vp8_recon_recon2 vp8_recon2b_armv6 + +#undef vp8_recon_recon4 +#define vp8_recon_recon4 vp8_recon4b_armv6 + +#undef vp8_recon_copy8x8 +#define vp8_recon_copy8x8 vp8_copy_mem8x8_v6 + +#undef vp8_recon_copy8x4 +#define vp8_recon_copy8x4 vp8_copy_mem8x4_v6 + +#undef vp8_recon_copy16x16 +#define vp8_recon_copy16x16 vp8_copy_mem16x16_v6 +#endif + +#if HAVE_ARMV7 +extern prototype_recon_block(vp8_recon_b_neon); +extern prototype_recon_block(vp8_recon2b_neon); +extern prototype_recon_block(vp8_recon4b_neon); + +extern prototype_copy_block(vp8_copy_mem8x8_neon); +extern prototype_copy_block(vp8_copy_mem8x4_neon); +extern prototype_copy_block(vp8_copy_mem16x16_neon); + +#undef vp8_recon_recon +#define vp8_recon_recon vp8_recon_b_neon + +#undef vp8_recon_recon2 +#define vp8_recon_recon2 vp8_recon2b_neon + +#undef vp8_recon_recon4 +#define vp8_recon_recon4 vp8_recon4b_neon + +#undef vp8_recon_copy8x8 +#define vp8_recon_copy8x8 vp8_copy_mem8x8_neon + +#undef vp8_recon_copy8x4 +#define vp8_recon_copy8x4 vp8_copy_mem8x4_neon + +#undef vp8_recon_copy16x16 +#define vp8_recon_copy16x16 vp8_copy_mem16x16_neon +#endif + +#endif
diff --git a/vp8/common/arm/reconintra4x4_arm.c b/vp8/common/arm/reconintra4x4_arm.c new file mode 100644 index 0000000..334d352 --- /dev/null +++ b/vp8/common/arm/reconintra4x4_arm.c
@@ -0,0 +1,408 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "vpx_mem/vpx_mem.h" +#include "reconintra.h" + +void vp8_predict_intra4x4(BLOCKD *x, + int b_mode, + unsigned char *predictor) +{ + int i, r, c; + + unsigned char *Above = *(x->base_dst) + x->dst - x->dst_stride; + unsigned char Left[4]; + unsigned char top_left = Above[-1]; + + Left[0] = (*(x->base_dst))[x->dst - 1]; + Left[1] = (*(x->base_dst))[x->dst - 1 + x->dst_stride]; + Left[2] = (*(x->base_dst))[x->dst - 1 + 2 * x->dst_stride]; + Left[3] = (*(x->base_dst))[x->dst - 1 + 3 * x->dst_stride]; + + switch (b_mode) + { + case B_DC_PRED: + { + int expected_dc = 0; + + for (i = 0; i < 4; i++) + { + expected_dc += Above[i]; + expected_dc += Left[i]; + } + + expected_dc = (expected_dc + 4) >> 3; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = expected_dc; + } + + predictor += 16; + } + } + break; + case B_TM_PRED: + { + // prediction similar to true_motion prediction + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int pred = Above[c] - top_left + Left[r]; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + predictor[c] = pred; + } + + predictor += 16; + } + } + break; + + case B_VE_PRED: + { + + unsigned int ap[4]; + ap[0] = (top_left + 2 * Above[0] + Above[1] + 2) >> 2; + ap[1] = (Above[0] + 2 * Above[1] + Above[2] + 2) >> 2; + ap[2] = (Above[1] + 2 * Above[2] + Above[3] + 2) >> 2; + ap[3] = (Above[2] + 2 * Above[3] + Above[4] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + + predictor[c] = ap[c]; + } + + predictor += 16; + } + + } + break; + + + case B_HE_PRED: + { + + unsigned int lp[4]; + lp[0] = (top_left + 2 * Left[0] + Left[1] + 2) >> 2; + lp[1] = (Left[0] + 2 * Left[1] + Left[2] + 2) >> 2; + lp[2] = (Left[1] + 2 * Left[2] + Left[3] + 2) >> 2; + lp[3] = (Left[2] + 2 * Left[3] + Left[3] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = lp[r]; + } + + predictor += 16; + } + } + break; + case B_LD_PRED: + { + unsigned char *ptr = Above; + predictor[0 * 16 + 0] = (ptr[0] + ptr[1] * 2 + ptr[2] + 2) >> 2; + predictor[0 * 16 + 1] = + predictor[1 * 16 + 0] = (ptr[1] + ptr[2] * 2 + ptr[3] + 2) >> 2; + predictor[0 * 16 + 2] = + predictor[1 * 16 + 1] = + predictor[2 * 16 + 0] = (ptr[2] + ptr[3] * 2 + ptr[4] + 2) >> 2; + predictor[0 * 16 + 3] = + predictor[1 * 16 + 2] = + predictor[2 * 16 + 1] = + predictor[3 * 16 + 0] = (ptr[3] + ptr[4] * 2 + ptr[5] + 2) >> 2; + predictor[1 * 16 + 3] = + predictor[2 * 16 + 2] = + predictor[3 * 16 + 1] = (ptr[4] + ptr[5] * 2 + ptr[6] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[3 * 16 + 2] = (ptr[5] + ptr[6] * 2 + ptr[7] + 2) >> 2; + predictor[3 * 16 + 3] = (ptr[6] + ptr[7] * 2 + ptr[7] + 2) >> 2; + + } + break; + case B_RD_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + predictor[3 * 16 + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[3 * 16 + 1] = + predictor[2 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[3 * 16 + 2] = + predictor[2 * 16 + 1] = + predictor[1 * 16 + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[3 * 16 + 3] = + predictor[2 * 16 + 2] = + predictor[1 * 16 + 1] = + predictor[0 * 16 + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[1 * 16 + 2] = + predictor[0 * 16 + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[1 * 16 + 3] = + predictor[0 * 16 + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + + } + break; + case B_VR_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + predictor[3 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[3 * 16 + 1] = + predictor[1 * 16 + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 1] = + predictor[0 * 16 + 0] = (pp[4] + pp[5] + 1) >> 1; + predictor[3 * 16 + 2] = + predictor[1 * 16 + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[0 * 16 + 1] = (pp[5] + pp[6] + 1) >> 1; + predictor[3 * 16 + 3] = + predictor[1 * 16 + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[0 * 16 + 2] = (pp[6] + pp[7] + 1) >> 1; + predictor[1 * 16 + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[7] + pp[8] + 1) >> 1; + + } + break; + case B_VL_PRED: + { + + unsigned char *pp = Above; + + predictor[0 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[1 * 16 + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[2 * 16 + 0] = + predictor[0 * 16 + 1] = (pp[1] + pp[2] + 1) >> 1; + predictor[1 * 16 + 1] = + predictor[3 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 1] = + predictor[0 * 16 + 2] = (pp[2] + pp[3] + 1) >> 1; + predictor[3 * 16 + 1] = + predictor[1 * 16 + 2] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[0 * 16 + 3] = + predictor[2 * 16 + 2] = (pp[3] + pp[4] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[3 * 16 + 2] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 3] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[3 * 16 + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + case B_HD_PRED: + { + unsigned char pp[9]; + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + predictor[3 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[3 * 16 + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[2 * 16 + 0] = + predictor[3 * 16 + 2] = (pp[1] + pp[2] + 1) >> 1; + predictor[2 * 16 + 1] = + predictor[3 * 16 + 3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[1 * 16 + 0] = (pp[2] + pp[3] + 1) >> 1; + predictor[2 * 16 + 3] = + predictor[1 * 16 + 1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[1 * 16 + 2] = + predictor[0 * 16 + 0] = (pp[3] + pp[4] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[0 * 16 + 1] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[0 * 16 + 2] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + + case B_HU_PRED: + { + unsigned char *pp = Left; + predictor[0 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[0 * 16 + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[0 * 16 + 2] = + predictor[1 * 16 + 0] = (pp[1] + pp[2] + 1) >> 1; + predictor[0 * 16 + 3] = + predictor[1 * 16 + 1] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[1 * 16 + 2] = + predictor[2 * 16 + 0] = (pp[2] + pp[3] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[2 * 16 + 1] = (pp[2] + pp[3] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[2 * 16 + 3] = + predictor[3 * 16 + 0] = + predictor[3 * 16 + 1] = + predictor[3 * 16 + 2] = + predictor[3 * 16 + 3] = pp[3]; + } + break; + + + } +} +// copy 4 bytes from the above right down so that the 4x4 prediction modes using pixels above and +// to the right prediction have filled in pixels to use. +void vp8_intra_prediction_down_copy(MACROBLOCKD *x) +{ + unsigned char *above_right = *(x->block[0].base_dst) + x->block[0].dst - x->block[0].dst_stride + 16; + + unsigned int *src_ptr = (unsigned int *)above_right; + unsigned int *dst_ptr0 = (unsigned int *)(above_right + 4 * x->block[0].dst_stride); + unsigned int *dst_ptr1 = (unsigned int *)(above_right + 8 * x->block[0].dst_stride); + unsigned int *dst_ptr2 = (unsigned int *)(above_right + 12 * x->block[0].dst_stride); + + *dst_ptr0 = *src_ptr; + *dst_ptr1 = *src_ptr; + *dst_ptr2 = *src_ptr; +} + + + +/* +void vp8_recon_intra4x4mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + vp8_intra_prediction_down_copy(x); + + for(i=0;i<16;i++) + { + BLOCKD *b = &x->block[i]; + + vp8_predict_intra4x4(b, x->block[i].bmi.mode,x->block[i].predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } + + vp8_recon_intra_mbuv(x); + +} +*/ +void vp8_recon_intra4x4mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + BLOCKD *b = &x->block[0]; + + vp8_intra_prediction_down_copy(x); + + { + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + b += 1; + + vp8_predict_intra4x4(b, b->bmi.mode, b->predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } + + vp8_recon_intra_mbuv(rtcd, x); + +}
diff --git a/vp8/common/arm/reconintra_arm.c b/vp8/common/arm/reconintra_arm.c new file mode 100644 index 0000000..d7ee1dd --- /dev/null +++ b/vp8/common/arm/reconintra_arm.c
@@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "blockd.h" +#include "reconintra.h" +#include "vpx_mem/vpx_mem.h" +#include "recon.h" + +#if HAVE_ARMV7 +extern void vp8_build_intra_predictors_mby_neon_func( + unsigned char *y_buffer, + unsigned char *ypred_ptr, + int y_stride, + int mode, + int Up, + int Left); + +void vp8_build_intra_predictors_mby_neon(MACROBLOCKD *x) +{ + unsigned char *y_buffer = x->dst.y_buffer; + unsigned char *ypred_ptr = x->predictor; + int y_stride = x->dst.y_stride; + int mode = x->mbmi.mode; + int Up = x->up_available; + int Left = x->left_available; + + vp8_build_intra_predictors_mby_neon_func(y_buffer, ypred_ptr, y_stride, mode, Up, Left); +} +#endif + + +#if HAVE_ARMV7 +extern void vp8_build_intra_predictors_mby_s_neon_func( + unsigned char *y_buffer, + unsigned char *ypred_ptr, + int y_stride, + int mode, + int Up, + int Left); + +void vp8_build_intra_predictors_mby_s_neon(MACROBLOCKD *x) +{ + unsigned char *y_buffer = x->dst.y_buffer; + unsigned char *ypred_ptr = x->predictor; + int y_stride = x->dst.y_stride; + int mode = x->mbmi.mode; + int Up = x->up_available; + int Left = x->left_available; + + vp8_build_intra_predictors_mby_s_neon_func(y_buffer, ypred_ptr, y_stride, mode, Up, Left); +} + +#endif
diff --git a/vp8/common/arm/subpixel_arm.h b/vp8/common/arm/subpixel_arm.h new file mode 100644 index 0000000..56aec55 --- /dev/null +++ b/vp8/common/arm/subpixel_arm.h
@@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef SUBPIXEL_ARM_H +#define SUBPIXEL_ARM_H + +#if HAVE_ARMV6 +extern prototype_subpixel_predict(vp8_sixtap_predict16x16_armv6); +extern prototype_subpixel_predict(vp8_sixtap_predict8x8_armv6); +extern prototype_subpixel_predict(vp8_sixtap_predict8x4_armv6); +extern prototype_subpixel_predict(vp8_sixtap_predict_armv6); +extern prototype_subpixel_predict(vp8_bilinear_predict16x16_armv6); +extern prototype_subpixel_predict(vp8_bilinear_predict8x8_armv6); +extern prototype_subpixel_predict(vp8_bilinear_predict8x4_armv6); +extern prototype_subpixel_predict(vp8_bilinear_predict4x4_armv6); + +#undef vp8_subpix_sixtap16x16 +#define vp8_subpix_sixtap16x16 vp8_sixtap_predict16x16_armv6 + +#undef vp8_subpix_sixtap8x8 +#define vp8_subpix_sixtap8x8 vp8_sixtap_predict8x8_armv6 + +#undef vp8_subpix_sixtap8x4 +#define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_armv6 + +#undef vp8_subpix_sixtap4x4 +#define vp8_subpix_sixtap4x4 vp8_sixtap_predict_armv6 + +#undef vp8_subpix_bilinear16x16 +#define vp8_subpix_bilinear16x16 vp8_bilinear_predict16x16_armv6 + +#undef vp8_subpix_bilinear8x8 +#define vp8_subpix_bilinear8x8 vp8_bilinear_predict8x8_armv6 + +#undef vp8_subpix_bilinear8x4 +#define vp8_subpix_bilinear8x4 vp8_bilinear_predict8x4_armv6 + +#undef vp8_subpix_bilinear4x4 +#define vp8_subpix_bilinear4x4 vp8_bilinear_predict4x4_armv6 +#endif + +#if HAVE_ARMV7 +extern prototype_subpixel_predict(vp8_sixtap_predict16x16_neon); +extern prototype_subpixel_predict(vp8_sixtap_predict8x8_neon); +extern prototype_subpixel_predict(vp8_sixtap_predict8x4_neon); +extern prototype_subpixel_predict(vp8_sixtap_predict_neon); +extern prototype_subpixel_predict(vp8_bilinear_predict16x16_neon); +extern prototype_subpixel_predict(vp8_bilinear_predict8x8_neon); +extern prototype_subpixel_predict(vp8_bilinear_predict8x4_neon); +extern prototype_subpixel_predict(vp8_bilinear_predict4x4_neon); + +#undef vp8_subpix_sixtap16x16 +#define vp8_subpix_sixtap16x16 vp8_sixtap_predict16x16_neon + +#undef vp8_subpix_sixtap8x8 +#define vp8_subpix_sixtap8x8 vp8_sixtap_predict8x8_neon + +#undef vp8_subpix_sixtap8x4 +#define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_neon + +#undef vp8_subpix_sixtap4x4 +#define vp8_subpix_sixtap4x4 vp8_sixtap_predict_neon + +#undef vp8_subpix_bilinear16x16 +#define vp8_subpix_bilinear16x16 vp8_bilinear_predict16x16_neon + +#undef vp8_subpix_bilinear8x8 +#define vp8_subpix_bilinear8x8 vp8_bilinear_predict8x8_neon + +#undef vp8_subpix_bilinear8x4 +#define vp8_subpix_bilinear8x4 vp8_bilinear_predict8x4_neon + +#undef vp8_subpix_bilinear4x4 +#define vp8_subpix_bilinear4x4 vp8_bilinear_predict4x4_neon +#endif + +#endif
diff --git a/vp8/common/arm/systemdependent.c b/vp8/common/arm/systemdependent.c new file mode 100644 index 0000000..ecc6929 --- /dev/null +++ b/vp8/common/arm/systemdependent.c
@@ -0,0 +1,148 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "g_common.h" +#include "pragmas.h" +#include "subpixel.h" +#include "loopfilter.h" +#include "recon.h" +#include "idct.h" +#include "onyxc_int.h" + +void (*vp8_build_intra_predictors_mby_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_neon(MACROBLOCKD *x); + +void (*vp8_build_intra_predictors_mby_s_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_s_neon(MACROBLOCKD *x); + +void vp8_machine_specific_config(VP8_COMMON *ctx) +{ +#if CONFIG_RUNTIME_CPU_DETECT + VP8_COMMON_RTCD *rtcd = &ctx->rtcd; + +#if HAVE_ARMV7 + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_neon; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_neon; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_neon; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_neon; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_neon; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_neon; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_neon; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_neon; + + rtcd->idct.idct1 = vp8_short_idct4x4llm_1_neon; + rtcd->idct.idct16 = vp8_short_idct4x4llm_neon; + rtcd->idct.idct1_scalar = vp8_dc_only_idct_neon; + rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_neon; + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_neon; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_neon; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_neon; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_neon; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_neon; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_neon; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_neon; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_neon; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_neon; + + rtcd->recon.copy16x16 = vp8_copy_mem16x16_neon; + rtcd->recon.copy8x8 = vp8_copy_mem8x8_neon; + rtcd->recon.copy8x4 = vp8_copy_mem8x4_neon; + rtcd->recon.recon = vp8_recon_b_neon; + rtcd->recon.recon2 = vp8_recon2b_neon; + rtcd->recon.recon4 = vp8_recon4b_neon; +#elif HAVE_ARMV6 + + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_armv6; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_armv6; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_armv6; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_armv6; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_armv6; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_armv6; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_armv6; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_armv6; + + rtcd->idct.idct1 = vp8_short_idct4x4llm_1_v6; + rtcd->idct.idct16 = vp8_short_idct4x4llm_v6_dual; + rtcd->idct.idct1_scalar = vp8_dc_only_idct_armv6; + rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_armv6; + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_armv6; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_armv6; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_armv6; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_armv6; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_armv6; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_armv6; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_armv6; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_armv6; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_armv6; + + rtcd->recon.copy16x16 = vp8_copy_mem16x16_v6; + rtcd->recon.copy8x8 = vp8_copy_mem8x8_v6; + rtcd->recon.copy8x4 = vp8_copy_mem8x4_v6; + rtcd->recon.recon = vp8_recon_b_armv6; + rtcd->recon.recon2 = vp8_recon2b_armv6; + rtcd->recon.recon4 = vp8_recon4b_armv6; +#else +//pure c + rtcd->idct.idct1 = vp8_short_idct4x4llm_1_c; + rtcd->idct.idct16 = vp8_short_idct4x4llm_c; + rtcd->idct.idct1_scalar = vp8_dc_only_idct_c; + rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_c; + + rtcd->recon.copy16x16 = vp8_copy_mem16x16_c; + rtcd->recon.copy8x8 = vp8_copy_mem8x8_c; + rtcd->recon.copy8x4 = vp8_copy_mem8x4_c; + rtcd->recon.recon = vp8_recon_b_c; + rtcd->recon.recon2 = vp8_recon2b_c; + rtcd->recon.recon4 = vp8_recon4b_c; + + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_c; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_c; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_c; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_c; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_c; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_c; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_c; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_c; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_c; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_c; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_c; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_c; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_c; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_c; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_c; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_c; +#endif + + rtcd->postproc.down = vp8_mbpost_proc_down_c; + rtcd->postproc.across = vp8_mbpost_proc_across_ip_c; + rtcd->postproc.downacross = vp8_post_proc_down_and_across_c; + rtcd->postproc.addnoise = vp8_plane_add_noise_c; +#endif + +#if HAVE_ARMV7 + vp8_build_intra_predictors_mby_ptr = vp8_build_intra_predictors_mby_neon; + vp8_build_intra_predictors_mby_s_ptr = vp8_build_intra_predictors_mby_s_neon; +#elif HAVE_ARMV6 + vp8_build_intra_predictors_mby_ptr = vp8_build_intra_predictors_mby; + vp8_build_intra_predictors_mby_s_ptr = vp8_build_intra_predictors_mby_s; +#else + vp8_build_intra_predictors_mby_ptr = vp8_build_intra_predictors_mby; + vp8_build_intra_predictors_mby_s_ptr = vp8_build_intra_predictors_mby_s; + +#endif + +}
diff --git a/vp8/common/arm/vpx_asm_offsets.c b/vp8/common/arm/vpx_asm_offsets.c new file mode 100644 index 0000000..68634bf --- /dev/null +++ b/vp8/common/arm/vpx_asm_offsets.c
@@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include <stddef.h> + +#if CONFIG_VP8_ENCODER +#include "vpx_scale/yv12config.h" +#endif + +#if CONFIG_VP8_DECODER +#include "onyxd_int.h" +#endif + +#define DEFINE(sym, val) int sym = val; + +/* +#define BLANK() asm volatile("\n->" : : ) +*/ + +/* + * int main(void) + * { + */ + +#if CONFIG_VP8_DECODER || CONFIG_VP8_ENCODER +DEFINE(yv12_buffer_config_y_width, offsetof(YV12_BUFFER_CONFIG, y_width)); +DEFINE(yv12_buffer_config_y_height, offsetof(YV12_BUFFER_CONFIG, y_height)); +DEFINE(yv12_buffer_config_y_stride, offsetof(YV12_BUFFER_CONFIG, y_stride)); +DEFINE(yv12_buffer_config_uv_width, offsetof(YV12_BUFFER_CONFIG, uv_width)); +DEFINE(yv12_buffer_config_uv_height, offsetof(YV12_BUFFER_CONFIG, uv_height)); +DEFINE(yv12_buffer_config_uv_stride, offsetof(YV12_BUFFER_CONFIG, uv_stride)); +DEFINE(yv12_buffer_config_y_buffer, offsetof(YV12_BUFFER_CONFIG, y_buffer)); +DEFINE(yv12_buffer_config_u_buffer, offsetof(YV12_BUFFER_CONFIG, u_buffer)); +DEFINE(yv12_buffer_config_v_buffer, offsetof(YV12_BUFFER_CONFIG, v_buffer)); +DEFINE(yv12_buffer_config_border, offsetof(YV12_BUFFER_CONFIG, border)); +#endif + +#if CONFIG_VP8_DECODER +DEFINE(mb_diff, offsetof(MACROBLOCKD, diff)); +DEFINE(mb_predictor, offsetof(MACROBLOCKD, predictor)); +DEFINE(mb_dst_y_stride, offsetof(MACROBLOCKD, dst.y_stride)); +DEFINE(mb_dst_y_buffer, offsetof(MACROBLOCKD, dst.y_buffer)); +DEFINE(mb_dst_u_buffer, offsetof(MACROBLOCKD, dst.u_buffer)); +DEFINE(mb_dst_v_buffer, offsetof(MACROBLOCKD, dst.v_buffer)); +DEFINE(mb_mbmi_mode, offsetof(MACROBLOCKD, mbmi.mode)); +DEFINE(mb_up_available, offsetof(MACROBLOCKD, up_available)); +DEFINE(mb_left_available, offsetof(MACROBLOCKD, left_available)); + +DEFINE(detok_scan, offsetof(DETOK, scan)); +DEFINE(detok_ptr_onyxblock2context_leftabove, offsetof(DETOK, ptr_onyxblock2context_leftabove)); +DEFINE(detok_onyx_coef_tree_ptr, offsetof(DETOK, vp8_coef_tree_ptr)); +DEFINE(detok_teb_base_ptr, offsetof(DETOK, teb_base_ptr)); +DEFINE(detok_norm_ptr, offsetof(DETOK, norm_ptr)); +DEFINE(detok_ptr_onyx_coef_bands_x, offsetof(DETOK, ptr_onyx_coef_bands_x)); + +DEFINE(DETOK_A, offsetof(DETOK, A)); +DEFINE(DETOK_L, offsetof(DETOK, L)); + +DEFINE(detok_qcoeff_start_ptr, offsetof(DETOK, qcoeff_start_ptr)); +DEFINE(detok_current_bc, offsetof(DETOK, current_bc)); +DEFINE(detok_coef_probs, offsetof(DETOK, coef_probs)); +DEFINE(detok_eob, offsetof(DETOK, eob)); + +DEFINE(bool_decoder_lowvalue, offsetof(BOOL_DECODER, lowvalue)); +DEFINE(bool_decoder_range, offsetof(BOOL_DECODER, range)); +DEFINE(bool_decoder_value, offsetof(BOOL_DECODER, value)); +DEFINE(bool_decoder_count, offsetof(BOOL_DECODER, count)); +DEFINE(bool_decoder_user_buffer, offsetof(BOOL_DECODER, user_buffer)); +DEFINE(bool_decoder_user_buffer_sz, offsetof(BOOL_DECODER, user_buffer_sz)); +DEFINE(bool_decoder_decode_buffer, offsetof(BOOL_DECODER, decode_buffer)); +DEFINE(bool_decoder_read_ptr, offsetof(BOOL_DECODER, read_ptr)); +DEFINE(bool_decoder_write_ptr, offsetof(BOOL_DECODER, write_ptr)); + +DEFINE(tokenextrabits_min_val, offsetof(TOKENEXTRABITS, min_val)); +DEFINE(tokenextrabits_length, offsetof(TOKENEXTRABITS, Length)); +#endif + +//add asserts for any offset that is not supported by assembly code +//add asserts for any size that is not supported by assembly code +/* + * return 0; + * } + */
diff --git a/vp8/common/bigend.h b/vp8/common/bigend.h new file mode 100644 index 0000000..6a91ba1 --- /dev/null +++ b/vp8/common/bigend.h
@@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _bigend_h +#define _bigend_h + +#if defined(__cplusplus) +extern "C" { +#endif + +#define invert2(x) ( (((x)>>8)&0x00ff) | (((x)<<8)&0xff00) ) +#define invert4(x) ( ((invert2(x)&0x0000ffff)<<16) | (invert2((x>>16))&0x0000ffff) ) + +#define high_byte(x) (unsigned char)x +#define mid2Byte(x) (unsigned char)(x >> 8) +#define mid1Byte(x) (unsigned char)(x >> 16) +#define low_byte(x) (unsigned char)(x >> 24) + +#define SWAPENDS 1 + +#if defined(__cplusplus) +} +#endif +#endif
diff --git a/vp8/common/blockd.c b/vp8/common/blockd.c new file mode 100644 index 0000000..53f5e72 --- /dev/null +++ b/vp8/common/blockd.c
@@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "blockd.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_setup_temp_context(TEMP_CONTEXT *t, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, int count) +{ + vpx_memcpy(t->l, l, sizeof(ENTROPY_CONTEXT) * count); + vpx_memcpy(t->a, a, sizeof(ENTROPY_CONTEXT) * count); +} + +const int vp8_block2left[25] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0, 1, 1, 0}; +const int vp8_block2above[25] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 0}; +const int vp8_block2type[25] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1}; +const int vp8_block2context[25] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3};
diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h new file mode 100644 index 0000000..84ed53a --- /dev/null +++ b/vp8/common/blockd.h
@@ -0,0 +1,299 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_BLOCKD_H +#define __INC_BLOCKD_H + +void vpx_log(const char *format, ...); + +#include "vpx_ports/config.h" +#include "vpx_scale/yv12config.h" +#include "mv.h" +#include "treecoder.h" +#include "subpixel.h" +#include "vpx_ports/mem.h" + +#define TRUE 1 +#define FALSE 0 + +//#define DCPRED 1 +#define DCPREDSIMTHRESH 0 +#define DCPREDCNTTHRESH 3 + +#define Y1CONTEXT 0 +#define UCONTEXT 1 +#define VCONTEXT 2 +#define Y2CONTEXT 3 + +#define MB_FEATURE_TREE_PROBS 3 +#define MAX_MB_SEGMENTS 4 + +#define MAX_REF_LF_DELTAS 4 +#define MAX_MODE_LF_DELTAS 4 + +// Segment Feature Masks +#define SEGMENT_DELTADATA 0 +#define SEGMENT_ABSDATA 1 + +typedef struct +{ + int r, c; +} POS; + + +typedef int ENTROPY_CONTEXT; + +typedef struct +{ + ENTROPY_CONTEXT l[4]; + ENTROPY_CONTEXT a[4]; +} TEMP_CONTEXT; + +extern void vp8_setup_temp_context(TEMP_CONTEXT *t, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, int count); +extern const int vp8_block2left[25]; +extern const int vp8_block2above[25]; +extern const int vp8_block2type[25]; +extern const int vp8_block2context[25]; + +#define VP8_COMBINEENTROPYCONTEXTS( Dest, A, B) \ + Dest = ((A)!=0) + ((B)!=0); + + +typedef enum +{ + KEY_FRAME = 0, + INTER_FRAME = 1 +} FRAME_TYPE; + +typedef enum +{ + DC_PRED, // average of above and left pixels + V_PRED, // vertical prediction + H_PRED, // horizontal prediction + TM_PRED, // Truemotion prediction + B_PRED, // block based prediction, each block has its own prediction mode + + NEARESTMV, + NEARMV, + ZEROMV, + NEWMV, + SPLITMV, + + MB_MODE_COUNT +} MB_PREDICTION_MODE; + +// Macroblock level features +typedef enum +{ + MB_LVL_ALT_Q = 0, // Use alternate Quantizer .... + MB_LVL_ALT_LF = 1, // Use alternate loop filter value... + MB_LVL_MAX = 2, // Number of MB level features supported + +} MB_LVL_FEATURES; + +// Segment Feature Masks +#define SEGMENT_ALTQ 0x01 +#define SEGMENT_ALT_LF 0x02 + +#define VP8_YMODES (B_PRED + 1) +#define VP8_UV_MODES (TM_PRED + 1) + +#define VP8_MVREFS (1 + SPLITMV - NEARESTMV) + +typedef enum +{ + B_DC_PRED, // average of above and left pixels + B_TM_PRED, + + B_VE_PRED, // vertical prediction + B_HE_PRED, // horizontal prediction + + B_LD_PRED, + B_RD_PRED, + + B_VR_PRED, + B_VL_PRED, + B_HD_PRED, + B_HU_PRED, + + LEFT4X4, + ABOVE4X4, + ZERO4X4, + NEW4X4, + + B_MODE_COUNT +} B_PREDICTION_MODE; + +#define VP8_BINTRAMODES (B_HU_PRED + 1) /* 10 */ +#define VP8_SUBMVREFS (1 + NEW4X4 - LEFT4X4) + +/* For keyframes, intra block modes are predicted by the (already decoded) + modes for the Y blocks to the left and above us; for interframes, there + is a single probability table. */ + +typedef struct +{ + B_PREDICTION_MODE mode; + union + { + int as_int; + MV as_mv; + } mv; +} B_MODE_INFO; + + +typedef enum +{ + INTRA_FRAME = 0, + LAST_FRAME = 1, + GOLDEN_FRAME = 2, + ALTREF_FRAME = 3, + MAX_REF_FRAMES = 4 +} MV_REFERENCE_FRAME; + +typedef struct +{ + MB_PREDICTION_MODE mode, uv_mode; + MV_REFERENCE_FRAME ref_frame; + union + { + int as_int; + MV as_mv; + } mv; + int partitioning; + int partition_count; + int mb_skip_coeff; //does this mb has coefficients at all, 1=no coefficients, 0=need decode tokens + int dc_diff; + unsigned char segment_id; // Which set of segmentation parameters should be used for this MB + int force_no_skip; + + B_MODE_INFO partition_bmi[16]; + +} MB_MODE_INFO; + + +typedef struct +{ + MB_MODE_INFO mbmi; + B_MODE_INFO bmi[16]; +} MODE_INFO; + + +typedef struct +{ + short *qcoeff; + short *dqcoeff; + unsigned char *predictor; + short *diff; + short *reference; + + short(*dequant)[4]; + + // 16 Y blocks, 4 U blocks, 4 V blocks each with 16 entries + unsigned char **base_pre; + int pre; + int pre_stride; + + unsigned char **base_dst; + int dst; + int dst_stride; + + int eob; + + B_MODE_INFO bmi; + +} BLOCKD; + +typedef struct +{ + DECLARE_ALIGNED(16, short, diff[400]); // from idct diff + DECLARE_ALIGNED(16, unsigned char, predictor[384]); + DECLARE_ALIGNED(16, short, reference[384]); + DECLARE_ALIGNED(16, short, qcoeff[400]); + DECLARE_ALIGNED(16, short, dqcoeff[400]); + + // 16 Y blocks, 4 U, 4 V, 1 DC 2nd order block, each with 16 entries. + BLOCKD block[25]; + + YV12_BUFFER_CONFIG pre; // Filtered copy of previous frame reconstruction + YV12_BUFFER_CONFIG dst; + + MODE_INFO *mode_info_context; + MODE_INFO *mode_info; + + int mode_info_stride; + + FRAME_TYPE frame_type; + + MB_MODE_INFO mbmi; + + int up_available; + int left_available; + + // Y,U,V,Y2 + ENTROPY_CONTEXT *above_context[4]; // row of context for each plane + ENTROPY_CONTEXT(*left_context)[4]; // (up to) 4 contexts "" + + // 0 indicates segmentation at MB level is not enabled. Otherwise the individual bits indicate which features are active. + unsigned char segmentation_enabled; + + // 0 (do not update) 1 (update) the macroblock segmentation map. + unsigned char update_mb_segmentation_map; + + // 0 (do not update) 1 (update) the macroblock segmentation feature data. + unsigned char update_mb_segmentation_data; + + // 0 (do not update) 1 (update) the macroblock segmentation feature data. + unsigned char mb_segement_abs_delta; + + // Per frame flags that define which MB level features (such as quantizer or loop filter level) + // are enabled and when enabled the proabilities used to decode the per MB flags in MB_MODE_INFO + vp8_prob mb_segment_tree_probs[MB_FEATURE_TREE_PROBS]; // Probability Tree used to code Segment number + + signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; // Segment parameters + + // mode_based Loop filter adjustment + unsigned char mode_ref_lf_delta_enabled; + unsigned char mode_ref_lf_delta_update; + + // Delta values have the range +/- MAX_LOOP_FILTER + //char ref_lf_deltas[MAX_REF_LF_DELTAS]; // 0 = Intra, Last, GF, ARF + //char mode_lf_deltas[MAX_MODE_LF_DELTAS]; // 0 = BPRED, ZERO_MV, MV, SPLIT + signed char ref_lf_deltas[MAX_REF_LF_DELTAS]; // 0 = Intra, Last, GF, ARF + signed char mode_lf_deltas[MAX_MODE_LF_DELTAS]; // 0 = BPRED, ZERO_MV, MV, SPLIT + + // Distance of MB away from frame edges + int mb_to_left_edge; + int mb_to_right_edge; + int mb_to_top_edge; + int mb_to_bottom_edge; + + //char * gf_active_ptr; + signed char *gf_active_ptr; + + unsigned int frames_since_golden; + unsigned int frames_till_alt_ref_frame; + vp8_subpix_fn_t subpixel_predict; + vp8_subpix_fn_t subpixel_predict8x4; + vp8_subpix_fn_t subpixel_predict8x8; + vp8_subpix_fn_t subpixel_predict16x16; + + void *current_bc; + +#if CONFIG_RUNTIME_CPU_DETECT + struct VP8_COMMON_RTCD *rtcd; +#endif +} MACROBLOCKD; + + +extern void vp8_build_block_doffsets(MACROBLOCKD *x); +extern void vp8_setup_block_dptrs(MACROBLOCKD *x); + +#endif /* __INC_BLOCKD_H */
diff --git a/vp8/common/boolcoder.h b/vp8/common/boolcoder.h new file mode 100644 index 0000000..0659d48 --- /dev/null +++ b/vp8/common/boolcoder.h
@@ -0,0 +1,569 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef bool_coder_h +#define bool_coder_h 1 + +/* Arithmetic bool coder with largish probability range. + Timothy S Murphy 6 August 2004 */ + +/* So as not to force users to drag in too much of my idiosyncratic C++ world, + I avoid fancy storage management. */ + +#include <assert.h> + +#include <stddef.h> +#include <stdio.h> + +typedef unsigned char vp8bc_index_t; // probability index + +/* There are a couple of slight variants in the details of finite-precision + arithmetic coding. May be safely ignored by most users. */ + +enum vp8bc_rounding +{ + vp8bc_down = 0, // just like VP8 + vp8bc_down_full = 1, // handles minimum probability correctly + vp8bc_up = 2 +}; + +#if _MSC_VER + +/* Note that msvc by default does not inline _anything_ (regardless of the + setting of inline_depth) and that a command-line option (-Ob1 or -Ob2) + is required to inline even the smallest functions. */ + +# pragma inline_depth( 255) // I mean it when I inline something +# pragma warning( disable : 4099) // No class vs. struct harassment +# pragma warning( disable : 4250) // dominance complaints +# pragma warning( disable : 4284) // operator-> in templates +# pragma warning( disable : 4800) // bool conversion + +// don't let prefix ++,-- stand in for postfix, disaster would ensue + +# pragma warning( error : 4620 4621) + +#endif // _MSC_VER + + +#if __cplusplus + +// Sometimes one wishes to be definite about integer lengths. + +struct int_types +{ + typedef const bool cbool; + typedef const signed char cchar; + typedef const short cshort; + typedef const int cint; + typedef const int clong; + + typedef const double cdouble; + typedef const size_t csize_t; + + typedef unsigned char uchar; // 8 bits + typedef const uchar cuchar; + + typedef short int16; + typedef unsigned short uint16; + typedef const int16 cint16; + typedef const uint16 cuint16; + + typedef int int32; + typedef unsigned int uint32; + typedef const int32 cint32; + typedef const uint32 cuint32; + + typedef unsigned int uint; + typedef unsigned int ulong; + typedef const uint cuint; + typedef const ulong culong; + + + // All structs consume space, may as well have a vptr. + + virtual ~int_types(); +}; + + +struct bool_coder_spec; +struct bool_coder; +struct bool_writer; +struct bool_reader; + + +struct bool_coder_namespace : int_types +{ + typedef vp8bc_index_t Index; + typedef bool_coder_spec Spec; + typedef const Spec c_spec; + + enum Rounding + { + Down = vp8bc_down, + down_full = vp8bc_down_full, + Up = vp8bc_up + }; +}; + + +// Archivable specification of a bool coder includes rounding spec +// and probability mapping table. The latter replaces a uchar j +// (0 <= j < 256) with an arbitrary uint16 tbl[j] = p. +// p/65536 is then the probability of a zero. + +struct bool_coder_spec : bool_coder_namespace +{ + friend struct bool_coder; + friend struct bool_writer; + friend struct bool_reader; + friend struct bool_coder_spec_float; + friend struct bool_coder_spec_explicit_table; + friend struct bool_coder_spec_exponential_table; + friend struct BPsrc; +private: + uint w; // precision + Rounding r; + + uint ebits, mbits, ebias; + uint32 mmask; + + Index max_index, half_index; + + uint32 mantissa(Index i) const + { + assert(i < half_index); + return (1 << mbits) + (i & mmask); + } + uint exponent(Index i) const + { + assert(i < half_index); + return ebias - (i >> mbits); + } + + uint16 Ptbl[256]; // kinda clunky, but so is storage management. + + /* Cost in bits of encoding a zero at every probability, scaled by 2^20. + Assumes that index is at most 8 bits wide. */ + + uint32 Ctbl[256]; + + uint32 split(Index i, uint32 R) const // 1 <= split <= max( 1, R-1) + { + if (!ebias) + return 1 + (((R - 1) * Ptbl[i]) >> 16); + + if (i >= half_index) + return R - split(max_index - i, R); + + return 1 + (((R - 1) * mantissa(i)) >> exponent(i)); + } + + uint32 max_range() const + { + return (1 << w) - (r == down_full ? 0 : 1); + } + uint32 min_range() const + { + return (1 << (w - 1)) + (r == down_full ? 1 : 0); + } + uint32 Rinc() const + { + return r == Up ? 1 : 0; + } + + void check_prec() const; + + bool float_init(uint Ebits, uint Mbits); + + void cost_init(); + + bool_coder_spec( + uint prec, Rounding rr, uint Ebits = 0, uint Mbits = 0 + ) + : w(prec), r(rr) + { + float_init(Ebits, Mbits); + } +public: + // Read complete spec from file. + bool_coder_spec(FILE *); + + // Write spec to file. + void dump(FILE *) const; + + // return probability index best approximating prob. + Index operator()(double prob) const; + + // probability corresponding to index + double operator()(Index i) const; + + Index complement(Index i) const + { + return max_index - i; + } + + Index max_index() const + { + return max_index; + } + Index half_index() const + { + return half_index; + } + + uint32 cost_zero(Index i) const + { + return Ctbl[i]; + } + uint32 cost_one(Index i) const + { + return Ctbl[ max_index - i]; + } + uint32 cost_bit(Index i, bool b) const + { + return Ctbl[b? max_index-i:i]; + } +}; + + +/* Pseudo floating-point probability specification. + + At least one of Ebits and Mbits must be nonzero. + + Since all arithmetic is done at 32 bits, Ebits is at most 5. + + Total significant bits in index is Ebits + Mbits + 1. + + Below the halfway point (i.e. when the top significant bit is 0), + the index is (e << Mbits) + m. + + The exponent e is between 0 and (2**Ebits) - 1, + the mantissa m is between 0 and (2**Mbits) - 1. + + Prepending an implicit 1 to the mantissa, the probability is then + + (2**Mbits + m) >> (e - 2**Ebits - 1 - Mbits), + + which has (1/2)**(2**Ebits + 1) as a minimum + and (1/2) * [1 - 2**(Mbits + 1)] as a maximum. + + When the index is above the halfway point, the probability is the + complement of the probability associated to the complement of the index. + + Note that the probability increases with the index and that, because of + the symmetry, we cannot encode probability exactly 1/2; though we + can get as close to 1/2 as we like, provided we have enough Mbits. + + The latter is of course not a problem in practice, one never has + exact probabilities and entropy errors are second order, that is, the + "overcoding" of a zero will be largely compensated for by the + "undercoding" of a one (or vice-versa). + + Compared to arithmetic probability specs (a la VP8), this will do better + at very high and low probabilities and worse at probabilities near 1/2, + as well as facilitating the usage of wider or narrower probability indices. +*/ + +struct bool_coder_spec_float : bool_coder_spec +{ + bool_coder_spec_float( + uint Ebits = 3, uint Mbits = 4, Rounding rr = down_full, uint prec = 12 + ) + : bool_coder_spec(prec, rr, Ebits, Mbits) + { + cost_init(); + } +}; + + +struct bool_coder_spec_explicit_table : bool_coder_spec +{ + bool_coder_spec_explicit_table( + cuint16 probability_table[256] = 0, // default is tbl[i] = i << 8. + Rounding = down_full, + uint precision = 16 + ); +}; + +// Contruct table via multiplicative interpolation between +// p[128] = 1/2 and p[0] = (1/2)^x. +// Since we are working with 16-bit precision, x is at most 16. +// For probabilities to increase with i, we must have x > 1. +// For 0 <= i <= 128, p[i] = (1/2)^{ 1 + [1 - (i/128)]*[x-1] }. +// Finally, p[128+i] = 1 - p[128 - i]. + +struct bool_coder_spec_exponential_table : bool_coder_spec +{ + bool_coder_spec_exponential_table(uint x, Rounding = down_full, uint prec = 16); +}; + + +// Commonalities between writer and reader. + +struct bool_coder : bool_coder_namespace +{ + friend struct bool_writer; + friend struct bool_reader; + friend struct BPsrc; +private: + uint32 Low, Range; + cuint32 min_range; + cuint32 rinc; + c_spec spec; + + void _reset() + { + Low = 0; + Range = spec.max_range(); + } + + bool_coder(c_spec &s) + : min_range(s.min_range()), + rinc(s.Rinc()), + spec(s) + { + _reset(); + } + + uint32 half() const + { + return 1 + ((Range - 1) >> 1); + } +public: + c_spec &Spec() const + { + return spec; + } +}; + + +struct bool_writer : bool_coder +{ + friend struct BPsrc; +private: + uchar *Bstart, *Bend, *B; + int bit_lag; + bool is_toast; + void carry(); + void reset() + { + _reset(); + bit_lag = 32 - spec.w; + is_toast = 0; + } + void raw(bool value, uint32 split); +public: + bool_writer(c_spec &, uchar *Dest, size_t Len); + virtual ~bool_writer(); + + void operator()(Index p, bool v) + { + raw(v, spec.split(p, Range)); + } + + uchar *buf() const + { + return Bstart; + } + size_t bytes_written() const + { + return B - Bstart; + } + + // Call when done with input, flushes internal state. + // DO NOT write any more data after calling this. + + bool_writer &flush(); + + void write_bits(int n, uint val) + { + if (n) + { + uint m = 1 << (n - 1); + + do + { + raw((bool)(val & m), half()); + } + while (m >>= 1); + } + } + +# if 0 + // We are agnostic about storage management. + // By default, overflows throw an assert but user can + // override to provide an expanding buffer using ... + + virtual void overflow(uint Len) const; + + // ... this function copies already-written data into new buffer + // and retains new buffer location. + + void new_buffer(uchar *dest, uint Len); + + // Note that storage management is the user's responsibility. +# endif +}; + + +// This could be adjusted to use a little less lookahead. + +struct bool_reader : bool_coder +{ + friend struct BPsrc; +private: + cuchar *const Bstart; // for debugging + cuchar *B; + cuchar *const Bend; + cuint shf; + uint bct; + bool raw(uint32 split); +public: + bool_reader(c_spec &s, cuchar *src, size_t Len); + + bool operator()(Index p) + { + return raw(spec.split(p, Range)); + } + + uint read_bits(int num_bits) + { + uint v = 0; + + while (--num_bits >= 0) + v += v + (raw(half()) ? 1 : 0); + + return v; + } +}; + +extern "C" { + +#endif /* __cplusplus */ + + + /* C interface */ + + typedef struct bool_coder_spec bool_coder_spec; + typedef struct bool_writer bool_writer; + typedef struct bool_reader bool_reader; + + typedef const bool_coder_spec c_bool_coder_spec; + typedef const bool_writer c_bool_writer; + typedef const bool_reader c_bool_reader; + + + /* Optionally override default precision when constructing coder_specs. + Just pass a zero pointer if you don't care. + Precision is at most 16 bits for table specs, at most 23 otherwise. */ + + struct vp8bc_prec + { + enum vp8bc_rounding r; /* see top header file for def */ + unsigned int prec; /* range precision in bits */ + }; + + typedef const struct vp8bc_prec vp8bc_c_prec; + + /* bool_coder_spec contains mapping of uchars to actual probabilities + (16 bit uints) as well as (usually immaterial) selection of + exact finite-precision algorithm used (for now, the latter can only + be overridden using the C++ interface). + See comments above the corresponding C++ constructors for discussion, + especially of exponential probability table generation. */ + + bool_coder_spec *vp8bc_vp8spec(); // just like vp8 + + bool_coder_spec *vp8bc_literal_spec( + const unsigned short prob_map[256], // 0 is like vp8 w/more precision + vp8bc_c_prec* + ); + + bool_coder_spec *vp8bc_float_spec( + unsigned int exponent_bits, unsigned int mantissa_bits, vp8bc_c_prec* + ); + + bool_coder_spec *vp8bc_exponential_spec(unsigned int min_exp, vp8bc_c_prec *); + + bool_coder_spec *vp8bc_spec_from_file(FILE *); + + + void vp8bc_destroy_spec(c_bool_coder_spec *); + + void vp8bc_spec_to_file(c_bool_coder_spec *, FILE *); + + + /* Nearest index to supplied probability of zero, 0 <= prob <= 1. */ + + vp8bc_index_t vp8bc_index(c_bool_coder_spec *, double prob); + + vp8bc_index_t vp8bc_index_from_counts( + c_bool_coder_spec *p, unsigned int zero_ct, unsigned int one_ct + ); + + /* In case you want to look */ + + double vp8bc_probability(c_bool_coder_spec *, vp8bc_index_t); + + /* Opposite index */ + + vp8bc_index_t vp8bc_complement(c_bool_coder_spec *, vp8bc_index_t); + + /* Cost in bits of encoding a zero at given probability, scaled by 2^20. + (assumes that an int holds at least 32 bits). */ + + unsigned int vp8bc_cost_zero(c_bool_coder_spec *, vp8bc_index_t); + + unsigned int vp8bc_cost_one(c_bool_coder_spec *, vp8bc_index_t); + unsigned int vp8bc_cost_bit(c_bool_coder_spec *, vp8bc_index_t, int); + + + /* bool_writer interface */ + + /* Length = 0 disables checking for writes beyond buffer end. */ + + bool_writer *vp8bc_create_writer( + c_bool_coder_spec *, unsigned char *Destination, size_t Length + ); + + /* Flushes out any buffered data and returns total # of bytes written. */ + + size_t vp8bc_destroy_writer(bool_writer *); + + void vp8bc_write_bool(bool_writer *, int boolean_val, vp8bc_index_t false_prob); + + void vp8bc_write_bits( + bool_writer *, unsigned int integer_value, int number_of_bits + ); + + c_bool_coder_spec *vp8bc_writer_spec(c_bool_writer *); + + + /* bool_reader interface */ + + /* Length = 0 disables checking for reads beyond buffer end. */ + + bool_reader *vp8bc_create_reader( + c_bool_coder_spec *, const unsigned char *Source, size_t Length + ); + void vp8bc_destroy_reader(bool_reader *); + + int vp8bc_read_bool(bool_reader *, vp8bc_index_t false_prob); + + unsigned int vp8bc_read_bits(bool_reader *, int number_of_bits); + + c_bool_coder_spec *vp8bc_reader_spec(c_bool_reader *); + +#if __cplusplus +} +#endif + +#endif /* bool_coder_h */
diff --git a/vp8/common/codec_common_interface.h b/vp8/common/codec_common_interface.h new file mode 100644 index 0000000..7881b0a --- /dev/null +++ b/vp8/common/codec_common_interface.h
@@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + +#ifndef CODEC_COMMON_INTERFACE_H +#define CODEC_COMMON_INTERFACE_H + +#define __export +#define _export +#define dll_export __declspec( dllexport ) +#define dll_import __declspec( dllimport ) + +// Playback ERROR Codes. +#define NO_DECODER_ERROR 0 +#define REMOTE_DECODER_ERROR -1 + +#define DFR_BAD_DCT_COEFF -100 +#define DFR_ZERO_LENGTH_FRAME -101 +#define DFR_FRAME_SIZE_INVALID -102 +#define DFR_OUTPUT_BUFFER_OVERFLOW -103 +#define DFR_INVALID_FRAME_HEADER -104 +#define FR_INVALID_MODE_TOKEN -110 +#define ETR_ALLOCATION_ERROR -200 +#define ETR_INVALID_ROOT_PTR -201 +#define SYNCH_ERROR -400 +#define BUFFER_UNDERFLOW_ERROR -500 +#define PB_IB_OVERFLOW_ERROR -501 + +// External error triggers +#define PB_HEADER_CHECKSUM_ERROR -601 +#define PB_DATA_CHECKSUM_ERROR -602 + +// DCT Error Codes +#define DDCT_EXPANSION_ERROR -700 +#define DDCT_INVALID_TOKEN_ERROR -701 + +// exception_errors +#define GEN_EXCEPTIONS -800 +#define EX_UNQUAL_ERROR -801 + +// Unrecoverable error codes +#define FATAL_PLAYBACK_ERROR -1000 +#define GEN_ERROR_CREATING_CDC -1001 +#define GEN_THREAD_CREATION_ERROR -1002 +#define DFR_CREATE_BMP_FAILED -1003 + +// YUV buffer configuration structure +typedef struct +{ + int y_width; + int y_height; + int y_stride; + + int uv_width; + int uv_height; + int uv_stride; + + unsigned char *y_buffer; + unsigned char *u_buffer; + unsigned char *v_buffer; + +} YUV_BUFFER_CONFIG; +typedef enum +{ + C_SET_KEY_FRAME, + C_SET_FIXED_Q, + C_SET_FIRSTPASS_FILE, + C_SET_EXPERIMENTAL_MIN, + C_SET_EXPERIMENTAL_MAX = C_SET_EXPERIMENTAL_MIN + 255, + C_SET_CHECKPROTECT, + C_SET_TESTMODE, + C_SET_INTERNAL_SIZE, + C_SET_RECOVERY_FRAME, + C_SET_REFERENCEFRAME, + C_SET_GOLDENFRAME + +#ifndef VP50_COMP_INTERFACE + // Specialist test facilities. +// C_VCAP_PARAMS, // DO NOT USE FOR NOW WITH VFW CODEC +#endif + +} C_SETTING; + +typedef unsigned long C_SET_VALUE; + + +#endif
diff --git a/vp8/common/coefupdateprobs.h b/vp8/common/coefupdateprobs.h new file mode 100644 index 0000000..99affd6 --- /dev/null +++ b/vp8/common/coefupdateprobs.h
@@ -0,0 +1,184 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/* Update probabilities for the nodes in the token entropy tree. + Generated file included by entropy.c */ + +const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1] = +{ + { + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255, }, + {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255, }, + {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255, }, + {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, +};
diff --git a/vp8/common/common.h b/vp8/common/common.h new file mode 100644 index 0000000..29f6d37 --- /dev/null +++ b/vp8/common/common.h
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef common_h +#define common_h 1 + +#include <assert.h> + +/* Interface header for common constant data structures and lookup tables */ + +#include "vpx_mem/vpx_mem.h" + +#include "common_types.h" + +/* Only need this for fixed-size arrays, for structs just assign. */ + +#define vp8_copy( Dest, Src) { \ + assert( sizeof( Dest) == sizeof( Src)); \ + vpx_memcpy( Dest, Src, sizeof( Src)); \ + } + +/* Use this for variably-sized arrays. */ + +#define vp8_copy_array( Dest, Src, N) { \ + assert( sizeof( *Dest) == sizeof( *Src)); \ + vpx_memcpy( Dest, Src, N * sizeof( *Src)); \ + } + +#define vp8_zero( Dest) vpx_memset( &Dest, 0, sizeof( Dest)); + +#define vp8_zero_array( Dest, N) vpx_memset( Dest, 0, N * sizeof( *Dest)); + + +#endif /* common_h */
diff --git a/vp8/common/common_types.h b/vp8/common/common_types.h new file mode 100644 index 0000000..deb5ed8 --- /dev/null +++ b/vp8/common/common_types.h
@@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_COMMON_TYPES +#define __INC_COMMON_TYPES + +#define TRUE 1 +#define FALSE 0 + +#endif
diff --git a/vp8/common/context.c b/vp8/common/context.c new file mode 100644 index 0000000..17ee8c3 --- /dev/null +++ b/vp8/common/context.c
@@ -0,0 +1,398 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "entropy.h" + +/* *** GENERATED FILE: DO NOT EDIT *** */ + +#if 0 +int Contexts[vp8_coef_counter_dimen]; + +const int default_contexts[vp8_coef_counter_dimen] = +{ + { + // Block Type ( 0 ) + { + // Coeff Band ( 0 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + { + // Coeff Band ( 1 ) + {30190, 26544, 225, 24, 4, 0, 0, 0, 0, 0, 0, 4171593,}, + {26846, 25157, 1241, 130, 26, 6, 1, 0, 0, 0, 0, 149987,}, + {10484, 9538, 1006, 160, 36, 18, 0, 0, 0, 0, 0, 15104,}, + }, + { + // Coeff Band ( 2 ) + {25842, 40456, 1126, 83, 11, 2, 0, 0, 0, 0, 0, 0,}, + {9338, 8010, 512, 73, 7, 3, 2, 0, 0, 0, 0, 43294,}, + {1047, 751, 149, 31, 13, 6, 1, 0, 0, 0, 0, 879,}, + }, + { + // Coeff Band ( 3 ) + {26136, 9826, 252, 13, 0, 0, 0, 0, 0, 0, 0, 0,}, + {8134, 5574, 191, 14, 2, 0, 0, 0, 0, 0, 0, 35302,}, + { 605, 677, 116, 9, 1, 0, 0, 0, 0, 0, 0, 611,}, + }, + { + // Coeff Band ( 4 ) + {10263, 15463, 283, 17, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2773, 2191, 128, 9, 2, 2, 0, 0, 0, 0, 0, 10073,}, + { 134, 125, 32, 4, 0, 2, 0, 0, 0, 0, 0, 50,}, + }, + { + // Coeff Band ( 5 ) + {10483, 2663, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2137, 1251, 27, 1, 1, 0, 0, 0, 0, 0, 0, 14362,}, + { 116, 156, 14, 2, 1, 0, 0, 0, 0, 0, 0, 190,}, + }, + { + // Coeff Band ( 6 ) + {40977, 27614, 412, 28, 0, 0, 0, 0, 0, 0, 0, 0,}, + {6113, 5213, 261, 22, 3, 0, 0, 0, 0, 0, 0, 26164,}, + { 382, 312, 50, 14, 2, 0, 0, 0, 0, 0, 0, 345,}, + }, + { + // Coeff Band ( 7 ) + { 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,}, + }, + }, + { + // Block Type ( 1 ) + { + // Coeff Band ( 0 ) + {3268, 19382, 1043, 250, 93, 82, 49, 26, 17, 8, 25, 82289,}, + {8758, 32110, 5436, 1832, 827, 668, 420, 153, 24, 0, 3, 52914,}, + {9337, 23725, 8487, 3954, 2107, 1836, 1069, 399, 59, 0, 0, 18620,}, + }, + { + // Coeff Band ( 1 ) + {12419, 8420, 452, 62, 9, 1, 0, 0, 0, 0, 0, 0,}, + {11715, 8705, 693, 92, 15, 7, 2, 0, 0, 0, 0, 53988,}, + {7603, 8585, 2306, 778, 270, 145, 39, 5, 0, 0, 0, 9136,}, + }, + { + // Coeff Band ( 2 ) + {15938, 14335, 1207, 184, 55, 13, 4, 1, 0, 0, 0, 0,}, + {7415, 6829, 1138, 244, 71, 26, 7, 0, 0, 0, 0, 9980,}, + {1580, 1824, 655, 241, 89, 46, 10, 2, 0, 0, 0, 429,}, + }, + { + // Coeff Band ( 3 ) + {19453, 5260, 201, 19, 0, 0, 0, 0, 0, 0, 0, 0,}, + {9173, 3758, 213, 22, 1, 1, 0, 0, 0, 0, 0, 9820,}, + {1689, 1277, 276, 51, 17, 4, 0, 0, 0, 0, 0, 679,}, + }, + { + // Coeff Band ( 4 ) + {12076, 10667, 620, 85, 19, 9, 5, 0, 0, 0, 0, 0,}, + {4665, 3625, 423, 55, 19, 9, 0, 0, 0, 0, 0, 5127,}, + { 415, 440, 143, 34, 20, 7, 2, 0, 0, 0, 0, 101,}, + }, + { + // Coeff Band ( 5 ) + {12183, 4846, 115, 11, 1, 0, 0, 0, 0, 0, 0, 0,}, + {4226, 3149, 177, 21, 2, 0, 0, 0, 0, 0, 0, 7157,}, + { 375, 621, 189, 51, 11, 4, 1, 0, 0, 0, 0, 198,}, + }, + { + // Coeff Band ( 6 ) + {61658, 37743, 1203, 94, 10, 3, 0, 0, 0, 0, 0, 0,}, + {15514, 11563, 903, 111, 14, 5, 0, 0, 0, 0, 0, 25195,}, + { 929, 1077, 291, 78, 14, 7, 1, 0, 0, 0, 0, 507,}, + }, + { + // Coeff Band ( 7 ) + { 0, 990, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 412, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1641,}, + { 0, 18, 7, 1, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + }, + { + // Block Type ( 2 ) + { + // Coeff Band ( 0 ) + { 953, 24519, 628, 120, 28, 12, 4, 0, 0, 0, 0, 2248798,}, + {1525, 25654, 2647, 617, 239, 143, 42, 5, 0, 0, 0, 66837,}, + {1180, 11011, 3001, 1237, 532, 448, 239, 54, 5, 0, 0, 7122,}, + }, + { + // Coeff Band ( 1 ) + {1356, 2220, 67, 10, 4, 1, 0, 0, 0, 0, 0, 0,}, + {1450, 2544, 102, 18, 4, 3, 0, 0, 0, 0, 0, 57063,}, + {1182, 2110, 470, 130, 41, 21, 0, 0, 0, 0, 0, 6047,}, + }, + { + // Coeff Band ( 2 ) + { 370, 3378, 200, 30, 5, 4, 1, 0, 0, 0, 0, 0,}, + { 293, 1006, 131, 29, 11, 0, 0, 0, 0, 0, 0, 5404,}, + { 114, 387, 98, 23, 4, 8, 1, 0, 0, 0, 0, 236,}, + }, + { + // Coeff Band ( 3 ) + { 579, 194, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 395, 213, 5, 1, 0, 0, 0, 0, 0, 0, 0, 4157,}, + { 119, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 300,}, + }, + { + // Coeff Band ( 4 ) + { 38, 557, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 21, 114, 12, 1, 0, 0, 0, 0, 0, 0, 0, 427,}, + { 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,}, + }, + { + // Coeff Band ( 5 ) + { 52, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 652,}, + { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + { + // Coeff Band ( 6 ) + { 640, 569, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 25, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0, 517,}, + { 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,}, + }, + { + // Coeff Band ( 7 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + }, + { + // Block Type ( 3 ) + { + // Coeff Band ( 0 ) + {2506, 20161, 2707, 767, 261, 178, 107, 30, 14, 3, 0, 100694,}, + {8806, 36478, 8817, 3268, 1280, 850, 401, 114, 42, 0, 0, 58572,}, + {11003, 27214, 11798, 5716, 2482, 2072, 1048, 175, 32, 0, 0, 19284,}, + }, + { + // Coeff Band ( 1 ) + {9738, 11313, 959, 205, 70, 18, 11, 1, 0, 0, 0, 0,}, + {12628, 15085, 1507, 273, 52, 19, 9, 0, 0, 0, 0, 54280,}, + {10701, 15846, 5561, 1926, 813, 570, 249, 36, 0, 0, 0, 6460,}, + }, + { + // Coeff Band ( 2 ) + {6781, 22539, 2784, 634, 182, 123, 20, 4, 0, 0, 0, 0,}, + {6263, 11544, 2649, 790, 259, 168, 27, 5, 0, 0, 0, 20539,}, + {3109, 4075, 2031, 896, 457, 386, 158, 29, 0, 0, 0, 1138,}, + }, + { + // Coeff Band ( 3 ) + {11515, 4079, 465, 73, 5, 14, 2, 0, 0, 0, 0, 0,}, + {9361, 5834, 650, 96, 24, 8, 4, 0, 0, 0, 0, 22181,}, + {4343, 3974, 1360, 415, 132, 96, 14, 1, 0, 0, 0, 1267,}, + }, + { + // Coeff Band ( 4 ) + {4787, 9297, 823, 168, 44, 12, 4, 0, 0, 0, 0, 0,}, + {3619, 4472, 719, 198, 60, 31, 3, 0, 0, 0, 0, 8401,}, + {1157, 1175, 483, 182, 88, 31, 8, 0, 0, 0, 0, 268,}, + }, + { + // Coeff Band ( 5 ) + {8299, 1226, 32, 5, 1, 0, 0, 0, 0, 0, 0, 0,}, + {3502, 1568, 57, 4, 1, 1, 0, 0, 0, 0, 0, 9811,}, + {1055, 1070, 166, 29, 6, 1, 0, 0, 0, 0, 0, 527,}, + }, + { + // Coeff Band ( 6 ) + {27414, 27927, 1989, 347, 69, 26, 0, 0, 0, 0, 0, 0,}, + {5876, 10074, 1574, 341, 91, 24, 4, 0, 0, 0, 0, 21954,}, + {1571, 2171, 778, 324, 124, 65, 16, 0, 0, 0, 0, 979,}, + }, + { + // Coeff Band ( 7 ) + { 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459,}, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,}, + }, + }, +}; + +//Update probabilities for the nodes in the token entropy tree. +const vp8_prob tree_update_probs[vp8_coef_tree_dimen] = +{ + { + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255, }, + {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255, }, + {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255, }, + {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255, }, + {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255, }, + }, + { + {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, + { + { + {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255, }, + {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, }, + {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + { + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, + }, + }, +}; +#endif
diff --git a/vp8/common/debugmodes.c b/vp8/common/debugmodes.c new file mode 100644 index 0000000..e2d2d2c --- /dev/null +++ b/vp8/common/debugmodes.c
@@ -0,0 +1,156 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdio.h> +#include "blockd.h" + + +void vp8_print_modes_and_motion_vectors(MODE_INFO *mi, int rows, int cols, int frame) +{ + + int mb_row; + int mb_col; + int mb_index = 0; + FILE *mvs = fopen("mvs.stt", "a"); + + // print out the macroblock Y modes + mb_index = 0; + fprintf(mvs, "Mb Modes for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.mode); + + mb_index++; + } + + fprintf(mvs, "\n"); + mb_index++; + } + + fprintf(mvs, "\n"); + + mb_index = 0; + fprintf(mvs, "Mb mv ref for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.ref_frame); + + mb_index++; + } + + fprintf(mvs, "\n"); + mb_index++; + } + + fprintf(mvs, "\n"); + + // print out the macroblock UV modes + mb_index = 0; + fprintf(mvs, "UV Modes for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + + fprintf(mvs, "%2d ", mi[mb_index].mbmi.uv_mode); + + mb_index++; + } + + mb_index++; + fprintf(mvs, "\n"); + } + + fprintf(mvs, "\n"); + + // print out the block modes + mb_index = 0; + fprintf(mvs, "Mbs for Frame %d\n", frame); + { + int b_row; + + for (b_row = 0; b_row < 4 * rows; b_row++) + { + int b_col; + int bindex; + + for (b_col = 0; b_col < 4 * cols; b_col++) + { + mb_index = (b_row >> 2) * (cols + 1) + (b_col >> 2); + bindex = (b_row & 3) * 4 + (b_col & 3); + + if (mi[mb_index].mbmi.mode == B_PRED) + fprintf(mvs, "%2d ", mi[mb_index].bmi[bindex].mode); + else + fprintf(mvs, "xx "); + + } + + fprintf(mvs, "\n"); + } + } + fprintf(mvs, "\n"); + + // print out the macroblock mvs + mb_index = 0; + fprintf(mvs, "MVs for Frame %d\n", frame); + + for (mb_row = 0; mb_row < rows; mb_row++) + { + for (mb_col = 0; mb_col < cols; mb_col++) + { + fprintf(mvs, "%5d:%-5d", mi[mb_index].mbmi.mv.as_mv.row / 2, mi[mb_index].mbmi.mv.as_mv.col / 2); + + mb_index++; + } + + mb_index++; + fprintf(mvs, "\n"); + } + + fprintf(mvs, "\n"); + + + // print out the block modes + mb_index = 0; + fprintf(mvs, "MVs for Frame %d\n", frame); + { + int b_row; + + for (b_row = 0; b_row < 4 * rows; b_row++) + { + int b_col; + int bindex; + + for (b_col = 0; b_col < 4 * cols; b_col++) + { + mb_index = (b_row >> 2) * (cols + 1) + (b_col >> 2); + bindex = (b_row & 3) * 4 + (b_col & 3); + fprintf(mvs, "%3d:%-3d ", mi[mb_index].bmi[bindex].mv.as_mv.row, mi[mb_index].bmi[bindex].mv.as_mv.col); + + } + + fprintf(mvs, "\n"); + } + } + fprintf(mvs, "\n"); + + + fclose(mvs); +}
diff --git a/vp8/common/defaultcoefcounts.h b/vp8/common/defaultcoefcounts.h new file mode 100644 index 0000000..ccdf326 --- /dev/null +++ b/vp8/common/defaultcoefcounts.h
@@ -0,0 +1,220 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/* Generated file, included by entropy.c */ + +static const unsigned int default_coef_counts [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens] = +{ + + { + // Block Type ( 0 ) + { + // Coeff Band ( 0 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + { + // Coeff Band ( 1 ) + {30190, 26544, 225, 24, 4, 0, 0, 0, 0, 0, 0, 4171593,}, + {26846, 25157, 1241, 130, 26, 6, 1, 0, 0, 0, 0, 149987,}, + {10484, 9538, 1006, 160, 36, 18, 0, 0, 0, 0, 0, 15104,}, + }, + { + // Coeff Band ( 2 ) + {25842, 40456, 1126, 83, 11, 2, 0, 0, 0, 0, 0, 0,}, + {9338, 8010, 512, 73, 7, 3, 2, 0, 0, 0, 0, 43294,}, + {1047, 751, 149, 31, 13, 6, 1, 0, 0, 0, 0, 879,}, + }, + { + // Coeff Band ( 3 ) + {26136, 9826, 252, 13, 0, 0, 0, 0, 0, 0, 0, 0,}, + {8134, 5574, 191, 14, 2, 0, 0, 0, 0, 0, 0, 35302,}, + { 605, 677, 116, 9, 1, 0, 0, 0, 0, 0, 0, 611,}, + }, + { + // Coeff Band ( 4 ) + {10263, 15463, 283, 17, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2773, 2191, 128, 9, 2, 2, 0, 0, 0, 0, 0, 10073,}, + { 134, 125, 32, 4, 0, 2, 0, 0, 0, 0, 0, 50,}, + }, + { + // Coeff Band ( 5 ) + {10483, 2663, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0,}, + {2137, 1251, 27, 1, 1, 0, 0, 0, 0, 0, 0, 14362,}, + { 116, 156, 14, 2, 1, 0, 0, 0, 0, 0, 0, 190,}, + }, + { + // Coeff Band ( 6 ) + {40977, 27614, 412, 28, 0, 0, 0, 0, 0, 0, 0, 0,}, + {6113, 5213, 261, 22, 3, 0, 0, 0, 0, 0, 0, 26164,}, + { 382, 312, 50, 14, 2, 0, 0, 0, 0, 0, 0, 345,}, + }, + { + // Coeff Band ( 7 ) + { 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,}, + }, + }, + { + // Block Type ( 1 ) + { + // Coeff Band ( 0 ) + {3268, 19382, 1043, 250, 93, 82, 49, 26, 17, 8, 25, 82289,}, + {8758, 32110, 5436, 1832, 827, 668, 420, 153, 24, 0, 3, 52914,}, + {9337, 23725, 8487, 3954, 2107, 1836, 1069, 399, 59, 0, 0, 18620,}, + }, + { + // Coeff Band ( 1 ) + {12419, 8420, 452, 62, 9, 1, 0, 0, 0, 0, 0, 0,}, + {11715, 8705, 693, 92, 15, 7, 2, 0, 0, 0, 0, 53988,}, + {7603, 8585, 2306, 778, 270, 145, 39, 5, 0, 0, 0, 9136,}, + }, + { + // Coeff Band ( 2 ) + {15938, 14335, 1207, 184, 55, 13, 4, 1, 0, 0, 0, 0,}, + {7415, 6829, 1138, 244, 71, 26, 7, 0, 0, 0, 0, 9980,}, + {1580, 1824, 655, 241, 89, 46, 10, 2, 0, 0, 0, 429,}, + }, + { + // Coeff Band ( 3 ) + {19453, 5260, 201, 19, 0, 0, 0, 0, 0, 0, 0, 0,}, + {9173, 3758, 213, 22, 1, 1, 0, 0, 0, 0, 0, 9820,}, + {1689, 1277, 276, 51, 17, 4, 0, 0, 0, 0, 0, 679,}, + }, + { + // Coeff Band ( 4 ) + {12076, 10667, 620, 85, 19, 9, 5, 0, 0, 0, 0, 0,}, + {4665, 3625, 423, 55, 19, 9, 0, 0, 0, 0, 0, 5127,}, + { 415, 440, 143, 34, 20, 7, 2, 0, 0, 0, 0, 101,}, + }, + { + // Coeff Band ( 5 ) + {12183, 4846, 115, 11, 1, 0, 0, 0, 0, 0, 0, 0,}, + {4226, 3149, 177, 21, 2, 0, 0, 0, 0, 0, 0, 7157,}, + { 375, 621, 189, 51, 11, 4, 1, 0, 0, 0, 0, 198,}, + }, + { + // Coeff Band ( 6 ) + {61658, 37743, 1203, 94, 10, 3, 0, 0, 0, 0, 0, 0,}, + {15514, 11563, 903, 111, 14, 5, 0, 0, 0, 0, 0, 25195,}, + { 929, 1077, 291, 78, 14, 7, 1, 0, 0, 0, 0, 507,}, + }, + { + // Coeff Band ( 7 ) + { 0, 990, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 412, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1641,}, + { 0, 18, 7, 1, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + }, + { + // Block Type ( 2 ) + { + // Coeff Band ( 0 ) + { 953, 24519, 628, 120, 28, 12, 4, 0, 0, 0, 0, 2248798,}, + {1525, 25654, 2647, 617, 239, 143, 42, 5, 0, 0, 0, 66837,}, + {1180, 11011, 3001, 1237, 532, 448, 239, 54, 5, 0, 0, 7122,}, + }, + { + // Coeff Band ( 1 ) + {1356, 2220, 67, 10, 4, 1, 0, 0, 0, 0, 0, 0,}, + {1450, 2544, 102, 18, 4, 3, 0, 0, 0, 0, 0, 57063,}, + {1182, 2110, 470, 130, 41, 21, 0, 0, 0, 0, 0, 6047,}, + }, + { + // Coeff Band ( 2 ) + { 370, 3378, 200, 30, 5, 4, 1, 0, 0, 0, 0, 0,}, + { 293, 1006, 131, 29, 11, 0, 0, 0, 0, 0, 0, 5404,}, + { 114, 387, 98, 23, 4, 8, 1, 0, 0, 0, 0, 236,}, + }, + { + // Coeff Band ( 3 ) + { 579, 194, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 395, 213, 5, 1, 0, 0, 0, 0, 0, 0, 0, 4157,}, + { 119, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 300,}, + }, + { + // Coeff Band ( 4 ) + { 38, 557, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 21, 114, 12, 1, 0, 0, 0, 0, 0, 0, 0, 427,}, + { 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,}, + }, + { + // Coeff Band ( 5 ) + { 52, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 652,}, + { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,}, + }, + { + // Coeff Band ( 6 ) + { 640, 569, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 25, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0, 517,}, + { 4, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,}, + }, + { + // Coeff Band ( 7 ) + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + }, + }, + { + // Block Type ( 3 ) + { + // Coeff Band ( 0 ) + {2506, 20161, 2707, 767, 261, 178, 107, 30, 14, 3, 0, 100694,}, + {8806, 36478, 8817, 3268, 1280, 850, 401, 114, 42, 0, 0, 58572,}, + {11003, 27214, 11798, 5716, 2482, 2072, 1048, 175, 32, 0, 0, 19284,}, + }, + { + // Coeff Band ( 1 ) + {9738, 11313, 959, 205, 70, 18, 11, 1, 0, 0, 0, 0,}, + {12628, 15085, 1507, 273, 52, 19, 9, 0, 0, 0, 0, 54280,}, + {10701, 15846, 5561, 1926, 813, 570, 249, 36, 0, 0, 0, 6460,}, + }, + { + // Coeff Band ( 2 ) + {6781, 22539, 2784, 634, 182, 123, 20, 4, 0, 0, 0, 0,}, + {6263, 11544, 2649, 790, 259, 168, 27, 5, 0, 0, 0, 20539,}, + {3109, 4075, 2031, 896, 457, 386, 158, 29, 0, 0, 0, 1138,}, + }, + { + // Coeff Band ( 3 ) + {11515, 4079, 465, 73, 5, 14, 2, 0, 0, 0, 0, 0,}, + {9361, 5834, 650, 96, 24, 8, 4, 0, 0, 0, 0, 22181,}, + {4343, 3974, 1360, 415, 132, 96, 14, 1, 0, 0, 0, 1267,}, + }, + { + // Coeff Band ( 4 ) + {4787, 9297, 823, 168, 44, 12, 4, 0, 0, 0, 0, 0,}, + {3619, 4472, 719, 198, 60, 31, 3, 0, 0, 0, 0, 8401,}, + {1157, 1175, 483, 182, 88, 31, 8, 0, 0, 0, 0, 268,}, + }, + { + // Coeff Band ( 5 ) + {8299, 1226, 32, 5, 1, 0, 0, 0, 0, 0, 0, 0,}, + {3502, 1568, 57, 4, 1, 1, 0, 0, 0, 0, 0, 9811,}, + {1055, 1070, 166, 29, 6, 1, 0, 0, 0, 0, 0, 527,}, + }, + { + // Coeff Band ( 6 ) + {27414, 27927, 1989, 347, 69, 26, 0, 0, 0, 0, 0, 0,}, + {5876, 10074, 1574, 341, 91, 24, 4, 0, 0, 0, 0, 21954,}, + {1571, 2171, 778, 324, 124, 65, 16, 0, 0, 0, 0, 979,}, + }, + { + // Coeff Band ( 7 ) + { 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + { 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459,}, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,}, + }, + }, +};
diff --git a/vp8/common/dma_desc.h b/vp8/common/dma_desc.h new file mode 100644 index 0000000..5e6fa0c --- /dev/null +++ b/vp8/common/dma_desc.h
@@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _dma_desc_h +#define _dma_desc_h + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define NDSIZE_LG 0x00000900 // Next Descriptor Size +#define NDSIZE_SM 0x00000800 // Next Descriptor Size +#define NDSIZE_7 0x00000700 // Next Descriptor Size +#define NDSIZE_6 0x00000600 // Next Descriptor Size +#define NDSIZE_5 0x00000500 // Next Descriptor Size +#define NDSIZE_4 0x00000400 // Next Descriptor Size +#define NDSIZE_3 0x00000300 // Next Descriptor Size +#define NDSIZE_2 0x00000200 // Next Descriptor Size +#define NDSIZE_1 0x00000100 // Next Descriptor Size + +#define FLOW_STOP 0x0000 +#define FLOW_AUTO 0x1000 +#define FLOW_DESC_AR 0x4000 +#define FLOW_DESC_SM 0x6000 +#define FLOW_DESC_LG 0x7000 + + typedef struct + { + unsigned int ndp; + //unsigned short ndpl; + //unsigned short ndph; + unsigned int sa; + //unsigned short sal; + //unsigned short sah; + + unsigned short dmacfg; + unsigned short xcnt; + unsigned short xmod; + unsigned short ycnt; + unsigned short ymod; + + } LARGE_DESC; + + typedef struct + { + unsigned short ndpl; + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + unsigned short xcnt; + unsigned short xmod; + unsigned short ycnt; + unsigned short ymod; + } SMALL_DESC; + + typedef struct + { + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + unsigned short xcnt; + unsigned short xmod; + unsigned short ycnt; + unsigned short ymod; + } ARRAY_DESC_7; + + typedef struct + { + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + unsigned short xcnt; + unsigned short xmod; + unsigned short ycnt; + } ARRAY_DESC_6; + + typedef struct + { + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + unsigned short xcnt; + unsigned short xmod; + } ARRAY_DESC_5; + + typedef struct + { + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + unsigned short xcnt; + } ARRAY_DESC_4; + + typedef struct + { + unsigned short sal; + unsigned short sah; + unsigned short dmacfg; + } ARRAY_DESC_3; + + typedef struct + { + unsigned short sal; + unsigned short sah; + } ARRAY_DESC_2; + + typedef struct + { + unsigned short sal; + } ARRAY_DESC_1; + +#if defined(__cplusplus) +} +#endif + +#endif //_dma_desc_h
diff --git a/vp8/common/duck_io.h b/vp8/common/duck_io.h new file mode 100644 index 0000000..f63a5cd --- /dev/null +++ b/vp8/common/duck_io.h
@@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _duck_io_h +#define _duck_io_h + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined (_WIN32) + typedef __int64 int64_t; +#elif defined(__MWERKS__) + typedef long long int64_t; +#elif defined(__APPLE__) || defined(__POWERPC) +#include <ppc/types.h> +#else + typedef long long int64_t; +#endif + + typedef struct + { + int64_t offset; // offset to start from + int blocking; // non-zero for blocking + } re_open_t; + + + typedef enum + { + SAL_ERR_MAX = -10, + SAL_ERROR = -11, // Default error + SAL_ERR_WSASTARTUP = -12, + SAL_ERR_SOCKET_CREATE = -13, + SAL_ERR_RESOLVING_HOSTNAME = -14, + SAL_ERR_SERVER_CONNECTION = -15, + SAL_ERR_SENDING_DATA = -16, + SAL_ERR_RECEIVING_DATA = -17, + SAL_ERR_404_FILE_NOT_FOUND = -18, + SAL_ERR_PARSING_HTTP_HEADER = -19, + SAL_ERR_PARSING_CONTENT_LEN = -20, + SAL_ERR_CONNECTION_TIMEOUT = -21, + SAL_ERR_FILE_OPEN_FAILED = -22, + SAL_ERR_MIN = -23 + } SAL_ERR; /* EMH 1-15-03 */ + + + typedef struct sal_err_map_temp + { + SAL_ERR code; + const char *decode; + + } sal_err_map_t; + + + static char *sal_err_text(SAL_ERR e) + { + int t; + const sal_err_map_t g_sal_err_map[] = + { + { SAL_ERR_WSASTARTUP, "Error with WSAStartup" }, + { SAL_ERR_SOCKET_CREATE, "Error creating socket" }, + { SAL_ERR_RESOLVING_HOSTNAME, "Error resolving hostname" }, + { SAL_ERR_SERVER_CONNECTION, "Error connecting to server" }, + { SAL_ERR_SENDING_DATA, "Error sending data" }, + { SAL_ERR_RECEIVING_DATA, "Error receiving data" }, + { SAL_ERR_404_FILE_NOT_FOUND, "Error file not found " }, + { SAL_ERR_PARSING_HTTP_HEADER, "Error parsing http header" }, + { SAL_ERR_PARSING_CONTENT_LEN, "Error parsing content length" }, + { SAL_ERR_CONNECTION_TIMEOUT, "Error Connection timed out" }, + { SAL_ERR_FILE_OPEN_FAILED, "Error opening file" } + }; + + for (t = 0; t < sizeof(g_sal_err_map) / sizeof(sal_err_map_t); t++) + { + if (e == g_sal_err_map[t].code) + return (char *) g_sal_err_map[t].decode; + } + + return 0; + } + + + + + + + + int duck_open(const char *fname, unsigned long user_data); + + void duck_close(int ghndl); + + int duck_read(int ghndl, unsigned char *buf, int nbytes); + + int64_t duck_seek(int g_hndl, int64_t offs, int origin); + + int duck_read_finished(int han, int flag); /* FWG 7-9-99 */ + + int duck_name(int handle, char name[], size_t max_len); /* EMH 9-23-03 */ + + int duck_read_blocking(int handle, unsigned char *buffer, int bytes); /* EMH 9-23-03 */ + + int64_t duck_available_data(int handle); /* EMH 10-23-03 */ + +#if defined(__cplusplus) +} +#endif + +#endif
diff --git a/vp8/common/entropy.c b/vp8/common/entropy.c new file mode 100644 index 0000000..e524c2a --- /dev/null +++ b/vp8/common/entropy.c
@@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdio.h> + +#include "entropy.h" +#include "string.h" +#include "blockd.h" +#include "onyxc_int.h" + +#define uchar unsigned char /* typedefs can clash */ +#define uint unsigned int + +typedef const uchar cuchar; +typedef const uint cuint; + +typedef vp8_prob Prob; + +#include "coefupdateprobs.h" + +DECLARE_ALIGNED(16, cuchar, vp8_coef_bands[16]) = { 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7}; +DECLARE_ALIGNED(16, cuchar, vp8_prev_token_class[MAX_ENTROPY_TOKENS]) = { 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0}; +DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]) = +{ + 0, 1, 4, 8, + 5, 2, 3, 6, + 9, 12, 13, 10, + 7, 11, 14, 15, +}; + +DECLARE_ALIGNED(16, short, vp8_default_zig_zag_mask[16]); + +const int vp8_mb_feature_data_bits[MB_LVL_MAX] = {7, 6}; + +/* Array indices are identical to previously-existing CONTEXT_NODE indices */ + +const vp8_tree_index vp8_coef_tree[ 22] = /* corresponding _CONTEXT_NODEs */ +{ + -DCT_EOB_TOKEN, 2, /* 0 = EOB */ + -ZERO_TOKEN, 4, /* 1 = ZERO */ + -ONE_TOKEN, 6, /* 2 = ONE */ + 8, 12, /* 3 = LOW_VAL */ + -TWO_TOKEN, 10, /* 4 = TWO */ + -THREE_TOKEN, -FOUR_TOKEN, /* 5 = THREE */ + 14, 16, /* 6 = HIGH_LOW */ + -DCT_VAL_CATEGORY1, -DCT_VAL_CATEGORY2, /* 7 = CAT_ONE */ + 18, 20, /* 8 = CAT_THREEFOUR */ + -DCT_VAL_CATEGORY3, -DCT_VAL_CATEGORY4, /* 9 = CAT_THREE */ + -DCT_VAL_CATEGORY5, -DCT_VAL_CATEGORY6 /* 10 = CAT_FIVE */ +}; + +struct vp8_token_struct vp8_coef_encodings[vp8_coef_tokens]; + +/* Trees for extra bits. Probabilities are constant and + do not depend on previously encoded bits */ + +static const Prob Pcat1[] = { 159}; +static const Prob Pcat2[] = { 165, 145}; +static const Prob Pcat3[] = { 173, 148, 140}; +static const Prob Pcat4[] = { 176, 155, 140, 135}; +static const Prob Pcat5[] = { 180, 157, 141, 134, 130}; +static const Prob Pcat6[] = +{ 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129}; + +static vp8_tree_index cat1[2], cat2[4], cat3[6], cat4[8], cat5[10], cat6[22]; + +void vp8_init_scan_order_mask() +{ + int i; + + for (i = 0; i < 16; i++) + { + vp8_default_zig_zag_mask[vp8_default_zig_zag1d[i]] = 1 << i; + } + +} + +static void init_bit_tree(vp8_tree_index *p, int n) +{ + int i = 0; + + while (++i < n) + { + p[0] = p[1] = i << 1; + p += 2; + } + + p[0] = p[1] = 0; +} + +static void init_bit_trees() +{ + init_bit_tree(cat1, 1); + init_bit_tree(cat2, 2); + init_bit_tree(cat3, 3); + init_bit_tree(cat4, 4); + init_bit_tree(cat5, 5); + init_bit_tree(cat6, 11); +} + + +static vp8bc_index_t bcc1[1], bcc2[2], bcc3[3], bcc4[4], bcc5[5], bcc6[11]; + +vp8_extra_bit_struct vp8_extra_bits[12] = +{ + { 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 1}, + { 0, 0, 0, 0, 2}, + { 0, 0, 0, 0, 3}, + { 0, 0, 0, 0, 4}, + { cat1, Pcat1, bcc1, 1, 5}, + { cat2, Pcat2, bcc2, 2, 7}, + { cat3, Pcat3, bcc3, 3, 11}, + { cat4, Pcat4, bcc4, 4, 19}, + { cat5, Pcat5, bcc5, 5, 35}, + { cat6, Pcat6, bcc6, 11, 67}, + { 0, 0, 0, 0, 0} +}; +#include "defaultcoefcounts.h" + +void vp8_default_coef_probs(VP8_COMMON *pc) +{ + int h = 0; + + do + { + int i = 0; + + do + { + int k = 0; + + do + { + unsigned int branch_ct [vp8_coef_tokens-1] [2]; + vp8_tree_probs_from_distribution( + vp8_coef_tokens, vp8_coef_encodings, vp8_coef_tree, + pc->fc.coef_probs [h][i][k], branch_ct, default_coef_counts [h][i][k], + 256, 1); + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++i < COEF_BANDS); + } + while (++h < BLOCK_TYPES); +} + + +void vp8_coef_tree_initialize() +{ + init_bit_trees(); + vp8_tokens_from_tree(vp8_coef_encodings, vp8_coef_tree); +}
diff --git a/vp8/common/entropy.h b/vp8/common/entropy.h new file mode 100644 index 0000000..1415832 --- /dev/null +++ b/vp8/common/entropy.h
@@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPY_H +#define __INC_ENTROPY_H + +#include "treecoder.h" +#include "blockd.h" + +/* Coefficient token alphabet */ + +#define ZERO_TOKEN 0 //0 Extra Bits 0+0 +#define ONE_TOKEN 1 //1 Extra Bits 0+1 +#define TWO_TOKEN 2 //2 Extra Bits 0+1 +#define THREE_TOKEN 3 //3 Extra Bits 0+1 +#define FOUR_TOKEN 4 //4 Extra Bits 0+1 +#define DCT_VAL_CATEGORY1 5 //5-6 Extra Bits 1+1 +#define DCT_VAL_CATEGORY2 6 //7-10 Extra Bits 2+1 +#define DCT_VAL_CATEGORY3 7 //11-26 Extra Bits 4+1 +#define DCT_VAL_CATEGORY4 8 //11-26 Extra Bits 5+1 +#define DCT_VAL_CATEGORY5 9 //27-58 Extra Bits 5+1 +#define DCT_VAL_CATEGORY6 10 //59+ Extra Bits 11+1 +#define DCT_EOB_TOKEN 11 //EOB Extra Bits 0+0 + +#define vp8_coef_tokens 12 +#define MAX_ENTROPY_TOKENS vp8_coef_tokens +#define ENTROPY_NODES 11 + +extern const vp8_tree_index vp8_coef_tree[]; + +extern struct vp8_token_struct vp8_coef_encodings[vp8_coef_tokens]; + +typedef struct +{ + vp8_tree_p tree; + const vp8_prob *prob; + vp8bc_index_t *prob_bc; + int Len; + int base_val; +} vp8_extra_bit_struct; + +extern vp8_extra_bit_struct vp8_extra_bits[12]; /* indexed by token value */ + +#define PROB_UPDATE_BASELINE_COST 7 + +#define MAX_PROB 255 +#define DCT_MAX_VALUE 2048 + + +/* Coefficients are predicted via a 3-dimensional probability table. */ + +/* Outside dimension. 0 = Y no DC, 1 = Y2, 2 = UV, 3 = Y with DC */ + +#define BLOCK_TYPES 4 + +/* Middle dimension is a coarsening of the coefficient's + position within the 4x4 DCT. */ + +#define COEF_BANDS 8 +extern DECLARE_ALIGNED(16, const unsigned char, vp8_coef_bands[16]); + +/* Inside dimension is 3-valued measure of nearby complexity, that is, + the extent to which nearby coefficients are nonzero. For the first + coefficient (DC, unless block type is 0), we look at the (already encoded) + blocks above and to the left of the current block. The context index is + then the number (0,1,or 2) of these blocks having nonzero coefficients. + After decoding a coefficient, the measure is roughly the size of the + most recently decoded coefficient (0 for 0, 1 for 1, 2 for >1). + Note that the intuitive meaning of this measure changes as coefficients + are decoded, e.g., prior to the first token, a zero means that my neighbors + are empty while, after the first token, because of the use of end-of-block, + a zero means we just decoded a zero and hence guarantees that a non-zero + coefficient will appear later in this block. However, this shift + in meaning is perfectly OK because our context depends also on the + coefficient band (and since zigzag positions 0, 1, and 2 are in + distinct bands). */ + +/*# define DC_TOKEN_CONTEXTS 3 // 00, 0!0, !0!0 */ +# define PREV_COEF_CONTEXTS 3 + +extern DECLARE_ALIGNED(16, const unsigned char, vp8_prev_token_class[vp8_coef_tokens]); + +extern const vp8_prob vp8_coef_update_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1]; + + +struct VP8Common; +void vp8_default_coef_probs(struct VP8Common *); + +extern DECLARE_ALIGNED(16, const int, vp8_default_zig_zag1d[16]); +extern short vp8_default_zig_zag_mask[16]; +extern const int vp8_mb_feature_data_bits[MB_LVL_MAX]; + +void vp8_coef_tree_initialize(void); +#endif
diff --git a/vp8/common/entropymode.c b/vp8/common/entropymode.c new file mode 100644 index 0000000..7dc1acd --- /dev/null +++ b/vp8/common/entropymode.c
@@ -0,0 +1,270 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "entropymode.h" +#include "entropy.h" +#include "vpx_mem/vpx_mem.h" + +static const unsigned int kf_y_mode_cts[VP8_YMODES] = { 1607, 915, 812, 811, 5455}; +static const unsigned int y_mode_cts [VP8_YMODES] = { 8080, 1908, 1582, 1007, 5874}; + +static const unsigned int uv_mode_cts [VP8_UV_MODES] = { 59483, 13605, 16492, 4230}; +static const unsigned int kf_uv_mode_cts[VP8_UV_MODES] = { 5319, 1904, 1703, 674}; + +static const unsigned int bmode_cts[VP8_BINTRAMODES] = +{ + 43891, 17694, 10036, 3920, 3363, 2546, 5119, 3221, 2471, 1723 +}; + +typedef enum +{ + SUBMVREF_NORMAL, + SUBMVREF_LEFT_ZED, + SUBMVREF_ABOVE_ZED, + SUBMVREF_LEFT_ABOVE_SAME, + SUBMVREF_LEFT_ABOVE_ZED +} sumvfref_t; + +int vp8_mv_cont(const MV *l, const MV *a) +{ + int lez = (l->row == 0 && l->col == 0); + int aez = (a->row == 0 && a->col == 0); + int lea = (l->row == a->row && l->col == a->col); + + if (lea && lez) + return SUBMVREF_LEFT_ABOVE_ZED; + + if (lea) + return SUBMVREF_LEFT_ABOVE_SAME; + + if (aez) + return SUBMVREF_ABOVE_ZED; + + if (lez) + return SUBMVREF_LEFT_ZED; + + return SUBMVREF_NORMAL; +} + +static const vp8_prob sub_mv_ref_prob [VP8_SUBMVREFS-1] = { 180, 162, 25}; + +const vp8_prob vp8_sub_mv_ref_prob2 [SUBMVREF_COUNT][VP8_SUBMVREFS-1] = +{ + { 147, 136, 18 }, + { 106, 145, 1 }, + { 179, 121, 1 }, + { 223, 1 , 34 }, + { 208, 1 , 1 } +}; + + + +vp8_mbsplit vp8_mbsplits [VP8_NUMMBSPLITS] = +{ + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + { + 0, 0, 1, 1, + 0, 0, 1, 1, + 0, 0, 1, 1, + 0, 0, 1, 1, + }, + { + 0, 0, 1, 1, + 0, 0, 1, 1, + 2, 2, 3, 3, + 2, 2, 3, 3, + }, + { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + }, +}; + +const int vp8_mbsplit_count [VP8_NUMMBSPLITS] = { 2, 2, 4, 16}; + +const vp8_prob vp8_mbsplit_probs [VP8_NUMMBSPLITS-1] = { 110, 111, 150}; + + +/* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */ + +const vp8_tree_index vp8_bmode_tree[18] = /* INTRAMODECONTEXTNODE value */ +{ + -B_DC_PRED, 2, /* 0 = DC_NODE */ + -B_TM_PRED, 4, /* 1 = TM_NODE */ + -B_VE_PRED, 6, /* 2 = VE_NODE */ + 8, 12, /* 3 = COM_NODE */ + -B_HE_PRED, 10, /* 4 = HE_NODE */ + -B_RD_PRED, -B_VR_PRED, /* 5 = RD_NODE */ + -B_LD_PRED, 14, /* 6 = LD_NODE */ + -B_VL_PRED, 16, /* 7 = VL_NODE */ + -B_HD_PRED, -B_HU_PRED /* 8 = HD_NODE */ +}; + +/* Again, these trees use the same probability indices as their + explicitly-programmed predecessors. */ + +const vp8_tree_index vp8_ymode_tree[8] = +{ + -DC_PRED, 2, + 4, 6, + -V_PRED, -H_PRED, + -TM_PRED, -B_PRED +}; + +const vp8_tree_index vp8_kf_ymode_tree[8] = +{ + -B_PRED, 2, + 4, 6, + -DC_PRED, -V_PRED, + -H_PRED, -TM_PRED +}; + +const vp8_tree_index vp8_uv_mode_tree[6] = +{ + -DC_PRED, 2, + -V_PRED, 4, + -H_PRED, -TM_PRED +}; + +const vp8_tree_index vp8_mbsplit_tree[6] = +{ + -3, 2, + -2, 4, + -0, -1 +}; + +const vp8_tree_index vp8_mv_ref_tree[8] = +{ + -ZEROMV, 2, + -NEARESTMV, 4, + -NEARMV, 6, + -NEWMV, -SPLITMV +}; + +const vp8_tree_index vp8_sub_mv_ref_tree[6] = +{ + -LEFT4X4, 2, + -ABOVE4X4, 4, + -ZERO4X4, -NEW4X4 +}; + + +struct vp8_token_struct vp8_bmode_encodings [VP8_BINTRAMODES]; +struct vp8_token_struct vp8_ymode_encodings [VP8_YMODES]; +struct vp8_token_struct vp8_kf_ymode_encodings [VP8_YMODES]; +struct vp8_token_struct vp8_uv_mode_encodings [VP8_UV_MODES]; +struct vp8_token_struct vp8_mbsplit_encodings [VP8_NUMMBSPLITS]; + +struct vp8_token_struct vp8_mv_ref_encoding_array [VP8_MVREFS]; +struct vp8_token_struct vp8_sub_mv_ref_encoding_array [VP8_SUBMVREFS]; + + +const vp8_tree_index vp8_small_mvtree [14] = +{ + 2, 8, + 4, 6, + -0, -1, + -2, -3, + 10, 12, + -4, -5, + -6, -7 +}; + +struct vp8_token_struct vp8_small_mvencodings [8]; + +void vp8_init_mbmode_probs(VP8_COMMON *x) +{ + unsigned int bct [VP8_YMODES] [2]; /* num Ymodes > num UV modes */ + + vp8_tree_probs_from_distribution( + VP8_YMODES, vp8_ymode_encodings, vp8_ymode_tree, + x->fc.ymode_prob, bct, y_mode_cts, + 256, 1 + ); + vp8_tree_probs_from_distribution( + VP8_YMODES, vp8_kf_ymode_encodings, vp8_kf_ymode_tree, + x->kf_ymode_prob, bct, kf_y_mode_cts, + 256, 1 + ); + vp8_tree_probs_from_distribution( + VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, + x->fc.uv_mode_prob, bct, uv_mode_cts, + 256, 1 + ); + vp8_tree_probs_from_distribution( + VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, + x->kf_uv_mode_prob, bct, kf_uv_mode_cts, + 256, 1 + ); + vpx_memcpy(x->fc.sub_mv_ref_prob, sub_mv_ref_prob, sizeof(sub_mv_ref_prob)); +} + + +static void intra_bmode_probs_from_distribution( + vp8_prob p [VP8_BINTRAMODES-1], + unsigned int branch_ct [VP8_BINTRAMODES-1] [2], + const unsigned int events [VP8_BINTRAMODES] +) +{ + vp8_tree_probs_from_distribution( + VP8_BINTRAMODES, vp8_bmode_encodings, vp8_bmode_tree, + p, branch_ct, events, + 256, 1 + ); +} + +void vp8_default_bmode_probs(vp8_prob p [VP8_BINTRAMODES-1]) +{ + unsigned int branch_ct [VP8_BINTRAMODES-1] [2]; + intra_bmode_probs_from_distribution(p, branch_ct, bmode_cts); +} + +void vp8_kf_default_bmode_probs(vp8_prob p [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]) +{ + unsigned int branch_ct [VP8_BINTRAMODES-1] [2]; + + int i = 0; + + do + { + int j = 0; + + do + { + intra_bmode_probs_from_distribution( + p[i][j], branch_ct, vp8_kf_default_bmode_counts[i][j]); + + } + while (++j < VP8_BINTRAMODES); + } + while (++i < VP8_BINTRAMODES); +} + + +void vp8_entropy_mode_init() +{ + vp8_tokens_from_tree(vp8_bmode_encodings, vp8_bmode_tree); + vp8_tokens_from_tree(vp8_ymode_encodings, vp8_ymode_tree); + vp8_tokens_from_tree(vp8_kf_ymode_encodings, vp8_kf_ymode_tree); + vp8_tokens_from_tree(vp8_uv_mode_encodings, vp8_uv_mode_tree); + vp8_tokens_from_tree(vp8_mbsplit_encodings, vp8_mbsplit_tree); + + vp8_tokens_from_tree(VP8_MVREFENCODINGS, vp8_mv_ref_tree); + vp8_tokens_from_tree(VP8_SUBMVREFENCODINGS, vp8_sub_mv_ref_tree); + + vp8_tokens_from_tree(vp8_small_mvencodings, vp8_small_mvtree); +}
diff --git a/vp8/common/entropymode.h b/vp8/common/entropymode.h new file mode 100644 index 0000000..ff630a4 --- /dev/null +++ b/vp8/common/entropymode.h
@@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPYMODE_H +#define __INC_ENTROPYMODE_H + +#include "onyxc_int.h" +#include "treecoder.h" + +typedef const int vp8_mbsplit[16]; + +#define VP8_NUMMBSPLITS 4 + +extern vp8_mbsplit vp8_mbsplits [VP8_NUMMBSPLITS]; + +extern const int vp8_mbsplit_count [VP8_NUMMBSPLITS]; /* # of subsets */ + +extern const vp8_prob vp8_mbsplit_probs [VP8_NUMMBSPLITS-1]; + +extern int vp8_mv_cont(const MV *l, const MV *a); +#define SUBMVREF_COUNT 5 +extern const vp8_prob vp8_sub_mv_ref_prob2 [SUBMVREF_COUNT][VP8_SUBMVREFS-1]; + + +extern const unsigned int vp8_kf_default_bmode_counts [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES]; + + +extern const vp8_tree_index vp8_bmode_tree[]; + +extern const vp8_tree_index vp8_ymode_tree[]; +extern const vp8_tree_index vp8_kf_ymode_tree[]; +extern const vp8_tree_index vp8_uv_mode_tree[]; + +extern const vp8_tree_index vp8_mbsplit_tree[]; +extern const vp8_tree_index vp8_mv_ref_tree[]; +extern const vp8_tree_index vp8_sub_mv_ref_tree[]; + +extern struct vp8_token_struct vp8_bmode_encodings [VP8_BINTRAMODES]; +extern struct vp8_token_struct vp8_ymode_encodings [VP8_YMODES]; +extern struct vp8_token_struct vp8_kf_ymode_encodings [VP8_YMODES]; +extern struct vp8_token_struct vp8_uv_mode_encodings [VP8_UV_MODES]; +extern struct vp8_token_struct vp8_mbsplit_encodings [VP8_NUMMBSPLITS]; + +/* Inter mode values do not start at zero */ + +extern struct vp8_token_struct vp8_mv_ref_encoding_array [VP8_MVREFS]; +extern struct vp8_token_struct vp8_sub_mv_ref_encoding_array [VP8_SUBMVREFS]; + +#define VP8_MVREFENCODINGS (vp8_mv_ref_encoding_array - NEARESTMV) +#define VP8_SUBMVREFENCODINGS (vp8_sub_mv_ref_encoding_array - LEFT4X4) + + +extern const vp8_tree_index vp8_small_mvtree[]; + +extern struct vp8_token_struct vp8_small_mvencodings [8]; + +void vp8_entropy_mode_init(void); + +void vp8_init_mbmode_probs(VP8_COMMON *x); + +void vp8_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES-1]); +void vp8_kf_default_bmode_probs(vp8_prob dest [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]); + +#endif
diff --git a/vp8/common/entropymv.c b/vp8/common/entropymv.c new file mode 100644 index 0000000..2b00c17 --- /dev/null +++ b/vp8/common/entropymv.c
@@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "entropymv.h" + +const MV_CONTEXT vp8_mv_update_probs[2] = +{ + {{ + 237, + 246, + 253, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 + }}, + {{ + 231, + 243, + 245, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 + }} +}; +const MV_CONTEXT vp8_default_mv_context[2] = +{ + {{ + // row + 162, // is short + 128, // sign + 225, 146, 172, 147, 214, 39, 156, // short tree + 128, 129, 132, 75, 145, 178, 206, 239, 254, 254 // long bits + }}, + + + + {{ + // same for column + 164, // is short + 128, + 204, 170, 119, 235, 140, 230, 228, + 128, 130, 130, 74, 148, 180, 203, 236, 254, 254 // long bits + + }} +};
diff --git a/vp8/common/entropymv.h b/vp8/common/entropymv.h new file mode 100644 index 0000000..d940c59 --- /dev/null +++ b/vp8/common/entropymv.h
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ENTROPYMV_H +#define __INC_ENTROPYMV_H + +#include "treecoder.h" + +enum +{ + mv_max = 1023, /* max absolute value of a MV component */ + MVvals = (2 * mv_max) + 1, /* # possible values "" */ + + mvlong_width = 10, /* Large MVs have 9 bit magnitudes */ + mvnum_short = 8, /* magnitudes 0 through 7 */ + + /* probability offsets for coding each MV component */ + + mvpis_short = 0, /* short (<= 7) vs long (>= 8) */ + MVPsign, /* sign for non-zero */ + MVPshort, /* 8 short values = 7-position tree */ + + MVPbits = MVPshort + mvnum_short - 1, /* mvlong_width long value bits */ + MVPcount = MVPbits + mvlong_width /* (with independent probabilities) */ +}; + +typedef struct mv_context +{ + vp8_prob prob[MVPcount]; /* often come in row, col pairs */ +} MV_CONTEXT; + +extern const MV_CONTEXT vp8_mv_update_probs[2], vp8_default_mv_context[2]; + +#endif
diff --git a/vp8/common/extend.c b/vp8/common/extend.c new file mode 100644 index 0000000..7407952 --- /dev/null +++ b/vp8/common/extend.c
@@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "extend.h" +#include "vpx_mem/vpx_mem.h" + + +static void extend_plane_borders +( + unsigned char *s, // source + int sp, // pitch + int h, // height + int w, // width + int et, // extend top border + int el, // extend left border + int eb, // extend bottom border + int er // extend right border +) +{ + + int i; + unsigned char *src_ptr1, *src_ptr2; + unsigned char *dest_ptr1, *dest_ptr2; + int linesize; + + // copy the left and right most columns out + src_ptr1 = s; + src_ptr2 = s + w - 1; + dest_ptr1 = s - el; + dest_ptr2 = s + w; + + for (i = 0; i < h - 0 + 1; i++) + { + vpx_memset(dest_ptr1, src_ptr1[0], el); + vpx_memset(dest_ptr2, src_ptr2[0], er); + src_ptr1 += sp; + src_ptr2 += sp; + dest_ptr1 += sp; + dest_ptr2 += sp; + } + + // Now copy the top and bottom source lines into each line of the respective borders + src_ptr1 = s - el; + src_ptr2 = s + sp * (h - 1) - el; + dest_ptr1 = s + sp * (-et) - el; + dest_ptr2 = s + sp * (h) - el; + linesize = el + er + w + 1; + + for (i = 0; i < (int)et; i++) + { + vpx_memcpy(dest_ptr1, src_ptr1, linesize); + dest_ptr1 += sp; + } + + for (i = 0; i < (int)eb; i++) + { + vpx_memcpy(dest_ptr2, src_ptr2, linesize); + dest_ptr2 += sp; + } +} + + +void vp8_extend_to_multiple_of16(YV12_BUFFER_CONFIG *ybf, int width, int height) +{ + int er = 0xf & (16 - (width & 0xf)); + int eb = 0xf & (16 - (height & 0xf)); + + // check for non multiples of 16 + if (er != 0 || eb != 0) + { + extend_plane_borders(ybf->y_buffer, ybf->y_stride, height, width, 0, 0, eb, er); + + //adjust for uv + height = (height + 1) >> 1; + width = (width + 1) >> 1; + er = 0x7 & (8 - (width & 0x7)); + eb = 0x7 & (8 - (height & 0x7)); + + if (er || eb) + { + extend_plane_borders(ybf->u_buffer, ybf->uv_stride, height, width, 0, 0, eb, er); + extend_plane_borders(ybf->v_buffer, ybf->uv_stride, height, width, 0, 0, eb, er); + } + } +} + +// note the extension is only for the last row, for intra prediction purpose +void vp8_extend_mb_row(YV12_BUFFER_CONFIG *ybf, unsigned char *YPtr, unsigned char *UPtr, unsigned char *VPtr) +{ + int i; + + YPtr += ybf->y_stride * 14; + UPtr += ybf->uv_stride * 6; + VPtr += ybf->uv_stride * 6; + + for (i = 0; i < 4; i++) + { + YPtr[i] = YPtr[-1]; + UPtr[i] = UPtr[-1]; + VPtr[i] = VPtr[-1]; + } + + YPtr += ybf->y_stride; + UPtr += ybf->uv_stride; + VPtr += ybf->uv_stride; + + for (i = 0; i < 4; i++) + { + YPtr[i] = YPtr[-1]; + UPtr[i] = UPtr[-1]; + VPtr[i] = VPtr[-1]; + } +}
diff --git a/vp8/common/extend.h b/vp8/common/extend.h new file mode 100644 index 0000000..6809ae7 --- /dev/null +++ b/vp8/common/extend.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_EXTEND_H +#define __INC_EXTEND_H + +#include "vpx_scale/yv12config.h" + +void Extend(YV12_BUFFER_CONFIG *ybf); +void vp8_extend_mb_row(YV12_BUFFER_CONFIG *ybf, unsigned char *YPtr, unsigned char *UPtr, unsigned char *VPtr); +void vp8_extend_to_multiple_of16(YV12_BUFFER_CONFIG *ybf, int width, int height); + +#endif
diff --git a/vp8/common/filter_c.c b/vp8/common/filter_c.c new file mode 100644 index 0000000..38991cb --- /dev/null +++ b/vp8/common/filter_c.c
@@ -0,0 +1,539 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> + +#define BLOCK_HEIGHT_WIDTH 4 +#define VP8_FILTER_WEIGHT 128 +#define VP8_FILTER_SHIFT 7 + + +static const int bilinear_filters[8][2] = +{ + { 128, 0 }, + { 112, 16 }, + { 96, 32 }, + { 80, 48 }, + { 64, 64 }, + { 48, 80 }, + { 32, 96 }, + { 16, 112 } +}; + + +static const short sub_pel_filters[8][6] = +{ + + { 0, 0, 128, 0, 0, 0 }, // note that 1/8 pel positions are just as per alpha -0.5 bicubic + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, // New 1/4 pel 6 tap filter + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, // New 1/2 pel 6 tap filter + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, // New 1/4 pel 6 tap filter + { 0, -1, 12, 123, -6, 0 }, + + + +}; + +void vp8_filter_block2d_first_pass +( + unsigned char *src_ptr, + int *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + (VP8_FILTER_WEIGHT >> 1); // Rounding + + // Normalize back to 0-255 + Temp = Temp >> VP8_FILTER_SHIFT; + + if (Temp < 0) + Temp = 0; + else if (Temp > 255) + Temp = 255; + + output_ptr[j] = Temp; + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +void vp8_filter_block2d_second_pass +( + int *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply filter + Temp = ((int)src_ptr[-2 * (int)pixel_step] * vp8_filter[0]) + + ((int)src_ptr[-1 * (int)pixel_step] * vp8_filter[1]) + + ((int)src_ptr[0] * vp8_filter[2]) + + ((int)src_ptr[pixel_step] * vp8_filter[3]) + + ((int)src_ptr[2*pixel_step] * vp8_filter[4]) + + ((int)src_ptr[3*pixel_step] * vp8_filter[5]) + + (VP8_FILTER_WEIGHT >> 1); // Rounding + + // Normalize back to 0-255 + Temp = Temp >> VP8_FILTER_SHIFT; + + if (Temp < 0) + Temp = 0; + else if (Temp > 255) + Temp = 255; + + output_ptr[j] = (unsigned char)Temp; + src_ptr++; + } + + // Start next row + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_pitch; + } +} + + +void vp8_filter_block2d +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + int output_pitch, + const short *HFilter, + const short *VFilter +) +{ + int FData[9*4]; // Temp data bufffer used in filtering + + // First filter 1-D horizontally... + vp8_filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 4, HFilter); + + // then filter verticaly... + vp8_filter_block2d_second_pass(FData + 8, output_ptr, output_pitch, 4, 4, 4, 4, VFilter); +} + + +void vp8_block_variation_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int *HVar, + int *VVar +) +{ + int i, j; + unsigned char *Ptr = src_ptr; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + *HVar += abs((int)Ptr[j] - (int)Ptr[j+1]); + *VVar += abs((int)Ptr[j] - (int)Ptr[j+src_pixels_per_line]); + } + + Ptr += src_pixels_per_line; + } +} + + + + +void vp8_sixtap_predict_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + vp8_filter_block2d(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter); +} +void vp8_sixtap_predict8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[13*16]; // Temp data bufffer used in filtering + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + // First filter 1-D horizontally... + vp8_filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 13, 8, HFilter); + + + // then filter verticaly... + vp8_filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 8, 8, VFilter); + +} + +void vp8_sixtap_predict8x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[13*16]; // Temp data bufffer used in filtering + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + // First filter 1-D horizontally... + vp8_filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 9, 8, HFilter); + + + // then filter verticaly... + vp8_filter_block2d_second_pass(FData + 16, dst_ptr, dst_pitch, 8, 8, 4, 8, VFilter); + +} + +void vp8_sixtap_predict16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const short *HFilter; + const short *VFilter; + int FData[21*24]; // Temp data bufffer used in filtering + + + HFilter = sub_pel_filters[xoffset]; // 6 tap + VFilter = sub_pel_filters[yoffset]; // 6 tap + + // First filter 1-D horizontally... + vp8_filter_block2d_first_pass(src_ptr - (2 * src_pixels_per_line), FData, src_pixels_per_line, 1, 21, 16, HFilter); + + // then filter verticaly... + vp8_filter_block2d_second_pass(FData + 32, dst_ptr, dst_pitch, 16, 16, 16, 16, VFilter); + +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_first_pass + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : INT32 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement first-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Produces INT32 output to retain precision for next pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +void vp8_filter_block2d_bil_first_pass +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + int pixel_step, + unsigned int output_height, + unsigned int output_width, + const int *vp8_filter +) +{ + unsigned int i, j; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply bilinear filter + output_ptr[j] = (((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2)) >> VP8_FILTER_SHIFT; + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_second_pass + * + * INPUTS : INT32 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement second-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Requires 32-bit input as produced by filter_block2d_bil_first_pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +void vp8_filter_block2d_bil_second_pass +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const int *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply filter + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2); + output_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_pitch; + } +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * INT32 *HFilter : Array of 2 horizontal filter taps. + * INT32 *VFilter : Array of 2 vertical filter taps. + * + * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : 2-D filters an input block by applying a 2-tap + * bi-linear filter horizontally followed by a 2-tap + * bi-linear filter vertically on the result. + * + * SPECIAL NOTES : The largest block size can be handled here is 16x16 + * + ****************************************************************************/ +void vp8_filter_block2d_bil +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int dst_pitch, + const int *HFilter, + const int *VFilter, + int Width, + int Height +) +{ + + unsigned short FData[17*16]; // Temp data bufffer used in filtering + + // First filter 1-D horizontally... + vp8_filter_block2d_bil_first_pass(src_ptr, FData, src_pixels_per_line, 1, Height + 1, Width, HFilter); + + // then 1-D vertically... + vp8_filter_block2d_bil_second_pass(FData, output_ptr, dst_pitch, Width, Width, Height, Width, VFilter); +} + + +void vp8_bilinear_predict4x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const int *HFilter; + const int *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; +#if 0 + { + int i; + unsigned char temp1[16]; + unsigned char temp2[16]; + + bilinear_predict4x4_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, temp1, 4); + vp8_filter_block2d_bil(src_ptr, temp2, src_pixels_per_line, 4, HFilter, VFilter, 4, 4); + + for (i = 0; i < 16; i++) + { + if (temp1[i] != temp2[i]) + { + bilinear_predict4x4_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, temp1, 4); + vp8_filter_block2d_bil(src_ptr, temp2, src_pixels_per_line, 4, HFilter, VFilter, 4, 4); + } + } + } +#endif + vp8_filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 4, 4); + +} + +void vp8_bilinear_predict8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const int *HFilter; + const int *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 8); + +} + +void vp8_bilinear_predict8x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const int *HFilter; + const int *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 8, 4); + +} + +void vp8_bilinear_predict16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + const int *HFilter; + const int *VFilter; + + HFilter = bilinear_filters[xoffset]; + VFilter = bilinear_filters[yoffset]; + + vp8_filter_block2d_bil(src_ptr, dst_ptr, src_pixels_per_line, dst_pitch, HFilter, VFilter, 16, 16); +}
diff --git a/vp8/common/findnearmv.c b/vp8/common/findnearmv.c new file mode 100644 index 0000000..fcb1f20 --- /dev/null +++ b/vp8/common/findnearmv.c
@@ -0,0 +1,207 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "findnearmv.h" + +#define FINDNEAR_SEARCH_SITES 3 + +/* Predict motion vectors using those from already-decoded nearby blocks. + Note that we only consider one 4x4 subblock from each candidate 16x16 + macroblock. */ + +typedef union +{ + unsigned int as_int; + MV as_mv; +} int_mv; /* facilitates rapid equality tests */ + +static void mv_bias(const MODE_INFO *x, int refframe, int_mv *mvp, const int *ref_frame_sign_bias) +{ + MV xmv; + xmv = x->mbmi.mv.as_mv; + + if (ref_frame_sign_bias[x->mbmi.ref_frame] != ref_frame_sign_bias[refframe]) + { + xmv.row *= -1; + xmv.col *= -1; + } + + mvp->as_mv = xmv; +} + + +void vp8_clamp_mv(MV *mv, const MACROBLOCKD *xd) +{ + if (mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; +} + + +void vp8_find_near_mvs +( + MACROBLOCKD *xd, + const MODE_INFO *here, + MV *nearest, + MV *nearby, + MV *best_mv, + int cnt[4], + int refframe, + int *ref_frame_sign_bias +) +{ + const MODE_INFO *above = here - xd->mode_info_stride; + const MODE_INFO *left = here - 1; + const MODE_INFO *aboveleft = above - 1; + int_mv near_mvs[4]; + int_mv *mv = near_mvs; + int *cntx = cnt; + enum {CNT_INTRA, CNT_NEAREST, CNT_NEAR, CNT_SPLITMV}; + + /* Zero accumulators */ + mv[0].as_int = mv[1].as_int = mv[2].as_int = 0; + cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0; + + /* Process above */ + if (above->mbmi.ref_frame != INTRA_FRAME) + { + if (above->mbmi.mv.as_int) + { + (++mv)->as_int = above->mbmi.mv.as_int; + mv_bias(above, refframe, mv, ref_frame_sign_bias); + ++cntx; + } + + *cntx += 2; + } + + /* Process left */ + if (left->mbmi.ref_frame != INTRA_FRAME) + { + if (left->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = left->mbmi.mv.as_int; + mv_bias(left, refframe, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != mv->as_int) + { + (++mv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 2; + } + else + cnt[CNT_INTRA] += 2; + } + + /* Process above left */ + if (aboveleft->mbmi.ref_frame != INTRA_FRAME) + { + if (aboveleft->mbmi.mv.as_int) + { + int_mv this_mv; + + this_mv.as_int = aboveleft->mbmi.mv.as_int; + mv_bias(aboveleft, refframe, &this_mv, ref_frame_sign_bias); + + if (this_mv.as_int != mv->as_int) + { + (++mv)->as_int = this_mv.as_int; + ++cntx; + } + + *cntx += 1; + } + else + cnt[CNT_INTRA] += 1; + } + + /* If we have three distinct MV's ... */ + if (cnt[CNT_SPLITMV]) + { + /* See if above-left MV can be merged with NEAREST */ + if (mv->as_int == near_mvs[CNT_NEAREST].as_int) + cnt[CNT_NEAREST] += 1; + } + + cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV) + + (left->mbmi.mode == SPLITMV)) * 2 + + (aboveleft->mbmi.mode == SPLITMV); + + /* Swap near and nearest if necessary */ + if (cnt[CNT_NEAR] > cnt[CNT_NEAREST]) + { + int tmp; + tmp = cnt[CNT_NEAREST]; + cnt[CNT_NEAREST] = cnt[CNT_NEAR]; + cnt[CNT_NEAR] = tmp; + tmp = near_mvs[CNT_NEAREST].as_int; + near_mvs[CNT_NEAREST].as_int = near_mvs[CNT_NEAR].as_int; + near_mvs[CNT_NEAR].as_int = tmp; + } + + /* Use near_mvs[0] to store the "best" MV */ + if (cnt[CNT_NEAREST] >= cnt[CNT_INTRA]) + near_mvs[CNT_INTRA] = near_mvs[CNT_NEAREST]; + + /* Set up return values */ + *best_mv = near_mvs[0].as_mv; + *nearest = near_mvs[CNT_NEAREST].as_mv; + *nearby = near_mvs[CNT_NEAR].as_mv; + + vp8_clamp_mv(nearest, xd); + vp8_clamp_mv(nearby, xd); + vp8_clamp_mv(best_mv, xd); //TODO: move this up before the copy +} + +vp8_prob *vp8_mv_ref_probs( + vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] +) +{ + p[0] = vp8_mode_contexts [near_mv_ref_ct[0]] [0]; + p[1] = vp8_mode_contexts [near_mv_ref_ct[1]] [1]; + p[2] = vp8_mode_contexts [near_mv_ref_ct[2]] [2]; + p[3] = vp8_mode_contexts [near_mv_ref_ct[3]] [3]; + //p[3] = vp8_mode_contexts [near_mv_ref_ct[1] + near_mv_ref_ct[2] + near_mv_ref_ct[3]] [3]; + return p; +} + +const B_MODE_INFO *vp8_left_bmi(const MODE_INFO *cur_mb, int b) +{ + if (!(b & 3)) + { + /* On L edge, get from MB to left of us */ + --cur_mb; + b += 4; + } + + return cur_mb->bmi + b - 1; +} + +const B_MODE_INFO *vp8_above_bmi(const MODE_INFO *cur_mb, int b, int mi_stride) +{ + if (!(b >> 2)) + { + /* On top edge, get from MB above us */ + cur_mb -= mi_stride; + b += 16; + } + + return cur_mb->bmi + b - 4; +}
diff --git a/vp8/common/findnearmv.h b/vp8/common/findnearmv.h new file mode 100644 index 0000000..2c02033 --- /dev/null +++ b/vp8/common/findnearmv.h
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_FINDNEARMV_H +#define __INC_FINDNEARMV_H + +#include "mv.h" +#include "blockd.h" +#include "modecont.h" +#include "treecoder.h" + +void vp8_find_near_mvs +( + MACROBLOCKD *xd, + const MODE_INFO *here, + MV *nearest, MV *nearby, MV *best, + int near_mv_ref_cts[4], + int refframe, + int *ref_frame_sign_bias +); + +vp8_prob *vp8_mv_ref_probs( + vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] +); + +const B_MODE_INFO *vp8_left_bmi(const MODE_INFO *cur_mb, int b); + +const B_MODE_INFO *vp8_above_bmi(const MODE_INFO *cur_mb, int b, int mi_stride); + +#define LEFT_TOP_MARGIN (16 << 3) +#define RIGHT_BOTTOM_MARGIN (16 << 3) + + +#endif
diff --git a/vp8/common/fourcc.hpp b/vp8/common/fourcc.hpp new file mode 100644 index 0000000..5f1faed --- /dev/null +++ b/vp8/common/fourcc.hpp
@@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef FOURCC_HPP +#define FOURCC_HPP + +#include <iosfwd> +#include <cstring> + + +#if defined(__POWERPC__) || defined(__APPLE__) || defined(__MERKS__) +using namespace std; +#endif + +class four_cc +{ +public: + + four_cc(); + four_cc(const char*); + explicit four_cc(unsigned long); + + bool operator==(const four_cc&) const; + bool operator!=(const four_cc&) const; + + bool operator==(const char*) const; + bool operator!=(const char*) const; + + operator unsigned long() const; + unsigned long as_long() const; + + four_cc& operator=(unsigned long); + + char operator[](int) const; + + std::ostream& put(std::ostream&) const; + + bool printable() const; + +private: + + union + { + char code[4]; + unsigned long code_as_long; + }; + +}; + + +inline four_cc::four_cc() +{ +} + +inline four_cc::four_cc(unsigned long x) + : code_as_long(x) +{ +} + +inline four_cc::four_cc(const char* str) +{ + memcpy(code, str, 4); +} + + +inline bool four_cc::operator==(const four_cc& rhs) const +{ + return code_as_long == rhs.code_as_long; +} + +inline bool four_cc::operator!=(const four_cc& rhs) const +{ + return !operator==(rhs); +} + +inline bool four_cc::operator==(const char* rhs) const +{ + return (memcmp(code, rhs, 4) == 0); +} + +inline bool four_cc::operator!=(const char* rhs) const +{ + return !operator==(rhs); +} + + +inline four_cc::operator unsigned long() const +{ + return code_as_long; +} + +inline unsigned long four_cc::as_long() const +{ + return code_as_long; +} + +inline char four_cc::operator[](int i) const +{ + return code[i]; +} + +inline four_cc& four_cc::operator=(unsigned long val) +{ + code_as_long = val; + return *this; +} + +inline std::ostream& operator<<(std::ostream& os, const four_cc& rhs) +{ + return rhs.put(os); +} + +#endif
diff --git a/vp8/common/g_common.h b/vp8/common/g_common.h new file mode 100644 index 0000000..e68c53e --- /dev/null +++ b/vp8/common/g_common.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +extern void (*vp8_clear_system_state)(void); +extern void (*vp8_plane_add_noise)(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int DPitch, int q); +extern void (*de_interlace) +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int Width, + int Height, + int Stride +);
diff --git a/vp8/common/generic/systemdependent.c b/vp8/common/generic/systemdependent.c new file mode 100644 index 0000000..0011ae0 --- /dev/null +++ b/vp8/common/generic/systemdependent.c
@@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "g_common.h" +#include "subpixel.h" +#include "loopfilter.h" +#include "recon.h" +#include "idct.h" +#include "onyxc_int.h" + +extern void vp8_arch_x86_common_init(VP8_COMMON *ctx); + +void (*vp8_build_intra_predictors_mby_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby(MACROBLOCKD *x); + +void (*vp8_build_intra_predictors_mby_s_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x); + +void vp8_machine_specific_config(VP8_COMMON *ctx) +{ +#if CONFIG_RUNTIME_CPU_DETECT + VP8_COMMON_RTCD *rtcd = &ctx->rtcd; + + rtcd->idct.idct1 = vp8_short_idct4x4llm_1_c; + rtcd->idct.idct16 = vp8_short_idct4x4llm_c; + rtcd->idct.idct1_scalar = vp8_dc_only_idct_c; + rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_c; + + rtcd->recon.copy16x16 = vp8_copy_mem16x16_c; + rtcd->recon.copy8x8 = vp8_copy_mem8x8_c; + rtcd->recon.copy8x4 = vp8_copy_mem8x4_c; + rtcd->recon.recon = vp8_recon_b_c; + rtcd->recon.recon2 = vp8_recon2b_c; + rtcd->recon.recon4 = vp8_recon4b_c; + + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_c; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_c; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_c; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict_c; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_c; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_c; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_c; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_c; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_c; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_c; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_c; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_c; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_c; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_c; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_c; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_c; + +#if CONFIG_POSTPROC || CONFIG_VP8_ENCODER + rtcd->postproc.down = vp8_mbpost_proc_down_c; + rtcd->postproc.across = vp8_mbpost_proc_across_ip_c; + rtcd->postproc.downacross = vp8_post_proc_down_and_across_c; + rtcd->postproc.addnoise = vp8_plane_add_noise_c; +#endif + +#endif + // Pure C: + vp8_build_intra_predictors_mby_ptr = vp8_build_intra_predictors_mby; + vp8_build_intra_predictors_mby_s_ptr = vp8_build_intra_predictors_mby_s; + +#if ARCH_X86 || ARCH_X86_64 + vp8_arch_x86_common_init(ctx); +#endif + +}
diff --git a/vp8/common/header.h b/vp8/common/header.h new file mode 100644 index 0000000..8b2b009 --- /dev/null +++ b/vp8/common/header.h
@@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_HEADER_H +#define __INC_HEADER_H + +/* 24 bits total */ +typedef struct +{ + unsigned int type: 1; + unsigned int version: 3; + unsigned int show_frame: 1; + + /* Allow 2^20 bytes = 8 megabits for first partition */ + + unsigned int first_partition_length_in_bytes: 19; + +#ifdef PACKET_TESTING + unsigned int frame_number; + unsigned int update_gold: 1; + unsigned int uses_gold: 1; + unsigned int update_last: 1; + unsigned int uses_last: 1; +#endif + +} VP8_HEADER; + +#ifdef PACKET_TESTING +#define VP8_HEADER_SIZE 8 +#else +#define VP8_HEADER_SIZE 3 +#endif + + +#endif
diff --git a/vp8/common/idct.h b/vp8/common/idct.h new file mode 100644 index 0000000..47b5f05 --- /dev/null +++ b/vp8/common/idct.h
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_IDCT_H +#define __INC_IDCT_H + +#define prototype_second_order(sym) \ + void sym(short *input, short *output) + +#define prototype_idct(sym) \ + void sym(short *input, short *output, int pitch) + +#define prototype_idct_scalar(sym) \ + void sym(short input, short *output, int pitch) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/idct_x86.h" +#endif + +#if ARCH_ARM +#include "arm/idct_arm.h" +#endif + +#ifndef vp8_idct_idct1 +#define vp8_idct_idct1 vp8_short_idct4x4llm_1_c +#endif +extern prototype_idct(vp8_idct_idct1); + +#ifndef vp8_idct_idct16 +#define vp8_idct_idct16 vp8_short_idct4x4llm_c +#endif +extern prototype_idct(vp8_idct_idct16); + +#ifndef vp8_idct_idct1_scalar +#define vp8_idct_idct1_scalar vp8_dc_only_idct_c +#endif +extern prototype_idct_scalar(vp8_idct_idct1_scalar); + + +#ifndef vp8_idct_iwalsh1 +#define vp8_idct_iwalsh1 vp8_short_inv_walsh4x4_1_c +#endif +extern prototype_second_order(vp8_idct_iwalsh1); + +#ifndef vp8_idct_iwalsh16 +#define vp8_idct_iwalsh16 vp8_short_inv_walsh4x4_c +#endif +extern prototype_second_order(vp8_idct_iwalsh16); + +typedef prototype_idct((*vp8_idct_fn_t)); +typedef prototype_idct_scalar((*vp8_idct_scalar_fn_t)); +typedef prototype_second_order((*vp8_second_order_fn_t)); + +typedef struct +{ + vp8_idct_fn_t idct1; + vp8_idct_fn_t idct16; + vp8_idct_scalar_fn_t idct1_scalar; + + vp8_second_order_fn_t iwalsh1; + vp8_second_order_fn_t iwalsh16; +} vp8_idct_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define IDCT_INVOKE(ctx,fn) (ctx)->fn +#else +#define IDCT_INVOKE(ctx,fn) vp8_idct_##fn +#endif + +#endif
diff --git a/vp8/common/idctllm.c b/vp8/common/idctllm.c new file mode 100644 index 0000000..57cf858 --- /dev/null +++ b/vp8/common/idctllm.c
@@ -0,0 +1,189 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** + * Notes: + * + * This implementation makes use of 16 bit fixed point verio of two multiply + * constants: + * 1. sqrt(2) * cos (pi/8) + * 2. sqrt(2) * sin (pi/8) + * Becuase the first constant is bigger than 1, to maintain the same 16 bit + * fixed point precision as the second one, we use a trick of + * x * a = x + x*(a-1) + * so + * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). + **************************************************************************/ +static const int cospi8sqrt2minus1 = 20091; +static const int sinpi8sqrt2 = 35468; +static const int rounding = 0; +void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + + short *ip = input; + short *op = output; + int temp1, temp2; + int shortpitch = pitch >> 1; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[8]; + b1 = ip[0] - ip[8]; + + temp1 = (ip[4] * sinpi8sqrt2 + rounding) >> 16; + temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1 + rounding) >> 16); + c1 = temp1 - temp2; + + temp1 = ip[4] + ((ip[4] * cospi8sqrt2minus1 + rounding) >> 16); + temp2 = (ip[12] * sinpi8sqrt2 + rounding) >> 16; + d1 = temp1 + temp2; + + op[shortpitch*0] = a1 + d1; + op[shortpitch*3] = a1 - d1; + + op[shortpitch*1] = b1 + c1; + op[shortpitch*2] = b1 - c1; + + ip++; + op++; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[2]; + b1 = ip[0] - ip[2]; + + temp1 = (ip[1] * sinpi8sqrt2 + rounding) >> 16; + temp2 = ip[3] + ((ip[3] * cospi8sqrt2minus1 + rounding) >> 16); + c1 = temp1 - temp2; + + temp1 = ip[1] + ((ip[1] * cospi8sqrt2minus1 + rounding) >> 16); + temp2 = (ip[3] * sinpi8sqrt2 + rounding) >> 16; + d1 = temp1 + temp2; + + + op[0] = (a1 + d1 + 4) >> 3; + op[3] = (a1 - d1 + 4) >> 3; + + op[1] = (b1 + c1 + 4) >> 3; + op[2] = (b1 - c1 + 4) >> 3; + + ip += shortpitch; + op += shortpitch; + } +} + +void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch) +{ + int i; + int a1; + short *op = output; + int shortpitch = pitch >> 1; + a1 = ((input[0] + 4) >> 3); + + for (i = 0; i < 4; i++) + { + op[0] = a1; + op[1] = a1; + op[2] = a1; + op[3] = a1; + op += shortpitch; + } +} + + +void vp8_dc_only_idct_c(short input_dc, short *output, int pitch) +{ + int i; + int a1; + short *op = output; + int shortpitch = pitch >> 1; + a1 = ((input_dc + 4) >> 3); + + for (i = 0; i < 4; i++) + { + op[0] = a1; + op[1] = a1; + op[2] = a1; + op[3] = a1; + op += shortpitch; + } +} + +void vp8_short_inv_walsh4x4_c(short *input, short *output) +{ + int i; + int a1, b1, c1, d1; + int a2, b2, c2, d2; + short *ip = input; + short *op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + op[0] = a1 + b1; + op[4] = c1 + d1; + op[8] = a1 - b1; + op[12] = d1 - c1; + ip++; + op++; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[3]; + b1 = ip[1] + ip[2]; + c1 = ip[1] - ip[2]; + d1 = ip[0] - ip[3]; + + a2 = a1 + b1; + b2 = c1 + d1; + c2 = a1 - b1; + d2 = d1 - c1; + + op[0] = (a2 + 3) >> 3; + op[1] = (b2 + 3) >> 3; + op[2] = (c2 + 3) >> 3; + op[3] = (d2 + 3) >> 3; + + ip += 4; + op += 4; + } +} + +void vp8_short_inv_walsh4x4_1_c(short *input, short *output) +{ + int i; + int a1; + short *op = output; + + a1 = ((input[0] + 3) >> 3); + + for (i = 0; i < 4; i++) + { + op[0] = a1; + op[1] = a1; + op[2] = a1; + op[3] = a1; + op += 4; + } +}
diff --git a/vp8/common/invtrans.c b/vp8/common/invtrans.c new file mode 100644 index 0000000..1ff596e --- /dev/null +++ b/vp8/common/invtrans.c
@@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "invtrans.h" + + + +static void recon_dcblock(MACROBLOCKD *x) +{ + BLOCKD *b = &x->block[24]; + int i; + + for (i = 0; i < 16; i++) + { + x->block[i].dqcoeff[0] = b->diff[i]; + } + +} + +void vp8_inverse_transform_b(const vp8_idct_rtcd_vtable_t *rtcd, BLOCKD *b, int pitch) +{ + if (b->eob > 1) + IDCT_INVOKE(rtcd, idct16)(b->dqcoeff, b->diff, pitch); + else + IDCT_INVOKE(rtcd, idct1)(b->dqcoeff, b->diff, pitch); +} + + +void vp8_inverse_transform_mby(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + // do 2nd order transform on the dc block + IDCT_INVOKE(rtcd, iwalsh16)(x->block[24].dqcoeff, x->block[24].diff); + + recon_dcblock(x); + + for (i = 0; i < 16; i++) + { + vp8_inverse_transform_b(rtcd, &x->block[i], 32); + } + +} +void vp8_inverse_transform_mbuv(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + for (i = 16; i < 24; i++) + { + vp8_inverse_transform_b(rtcd, &x->block[i], 16); + } + +} + + +void vp8_inverse_transform_mb(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + // do 2nd order transform on the dc block + + IDCT_INVOKE(rtcd, iwalsh16)(&x->block[24].dqcoeff[0], x->block[24].diff); + recon_dcblock(x); + } + + for (i = 0; i < 16; i++) + { + vp8_inverse_transform_b(rtcd, &x->block[i], 32); + } + + + for (i = 16; i < 24; i++) + { + vp8_inverse_transform_b(rtcd, &x->block[i], 16); + } + +}
diff --git a/vp8/common/invtrans.h b/vp8/common/invtrans.h new file mode 100644 index 0000000..93a40f9 --- /dev/null +++ b/vp8/common/invtrans.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_INVTRANS_H +#define __INC_INVTRANS_H + +#include "vpx_ports/config.h" +#include "idct.h" +#include "blockd.h" +extern void vp8_inverse_transform_b(const vp8_idct_rtcd_vtable_t *rtcd, BLOCKD *b, int pitch); +extern void vp8_inverse_transform_mb(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +extern void vp8_inverse_transform_mby(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +extern void vp8_inverse_transform_mbuv(const vp8_idct_rtcd_vtable_t *rtcd, MACROBLOCKD *x); + +#endif
diff --git a/vp8/common/littlend.h b/vp8/common/littlend.h new file mode 100644 index 0000000..08c525c --- /dev/null +++ b/vp8/common/littlend.h
@@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _littlend_h +#define _littlend_h + +#if defined(__cplusplus) +extern "C" { +#endif + +#define invert2(x) (x) +#define invert4(x) (x) + +#define low_byte(x) (unsigned char)x +#define mid1Byte(x) (unsigned char)(x >> 8) +#define mid2Byte(x) (unsigned char)(x >> 16) +#define high_byte(x) (unsigned char)(x >> 24) + +#define SWAPENDS 0 + +#if defined(__cplusplus) +} +#endif + +#endif
diff --git a/vp8/common/loopfilter.c b/vp8/common/loopfilter.c new file mode 100644 index 0000000..79e6177 --- /dev/null +++ b/vp8/common/loopfilter.c
@@ -0,0 +1,601 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "loopfilter.h" +#include "onyxc_int.h" + +typedef unsigned char uc; + + +prototype_loopfilter(vp8_loop_filter_horizontal_edge_c); +prototype_loopfilter(vp8_loop_filter_vertical_edge_c); +prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_c); +prototype_loopfilter(vp8_mbloop_filter_vertical_edge_c); +prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_c); +prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_c); + +// Horizontal MB filtering +void vp8_loop_filter_mbh_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_horizontal_edge_c(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_c(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_c(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + +void vp8_loop_filter_mbhs_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_c(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Vertical MB Filtering +void vp8_loop_filter_mbv_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_vertical_edge_c(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_c(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_c(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + +void vp8_loop_filter_mbvs_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_c(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + +// Horizontal B Filtering +void vp8_loop_filter_bh_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_c(u_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_c(v_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + +void vp8_loop_filter_bhs_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_c(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + +// Vertical B Filtering +void vp8_loop_filter_bv_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_vertical_edge_c(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_c(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_c(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_c(u_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_c(v_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + +void vp8_loop_filter_bvs_c(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_c(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + +void vp8_init_loop_filter(VP8_COMMON *cm) +{ + loop_filter_info *lfi = cm->lf_info; + LOOPFILTERTYPE lft = cm->filter_type; + int sharpness_lvl = cm->sharpness_level; + int frame_type = cm->frame_type; + int i, j; + + int block_inside_limit = 0; + int HEVThresh; + const int yhedge_boost = 2; + const int uvhedge_boost = 2; + + // For each possible value for the loop filter fill out a "loop_filter_info" entry. + for (i = 0; i <= MAX_LOOP_FILTER; i++) + { + int filt_lvl = i; + + if (frame_type == KEY_FRAME) + { + if (filt_lvl >= 40) + HEVThresh = 2; + else if (filt_lvl >= 15) + HEVThresh = 1; + else + HEVThresh = 0; + } + else + { + if (filt_lvl >= 40) + HEVThresh = 3; + else if (filt_lvl >= 20) + HEVThresh = 2; + else if (filt_lvl >= 15) + HEVThresh = 1; + else + HEVThresh = 0; + } + + // Set loop filter paramaeters that control sharpness. + block_inside_limit = filt_lvl >> (sharpness_lvl > 0); + block_inside_limit = block_inside_limit >> (sharpness_lvl > 4); + + if (sharpness_lvl > 0) + { + if (block_inside_limit > (9 - sharpness_lvl)) + block_inside_limit = (9 - sharpness_lvl); + } + + if (block_inside_limit < 1) + block_inside_limit = 1; + + for (j = 0; j < 16; j++) + { + lfi[i].lim[j] = block_inside_limit; + lfi[i].mbflim[j] = filt_lvl + yhedge_boost; + lfi[i].mbthr[j] = HEVThresh; + lfi[i].flim[j] = filt_lvl; + lfi[i].thr[j] = HEVThresh; + lfi[i].uvlim[j] = block_inside_limit; + lfi[i].uvmbflim[j] = filt_lvl + uvhedge_boost; + lfi[i].uvmbthr[j] = HEVThresh; + lfi[i].uvflim[j] = filt_lvl; + lfi[i].uvthr[j] = HEVThresh; + } + + } + + // Set up the function pointers depending on the type of loop filtering selected + if (lft == NORMAL_LOOPFILTER) + { + cm->lf_mbv = LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_v); + cm->lf_bv = LF_INVOKE(&cm->rtcd.loopfilter, normal_b_v); + cm->lf_mbh = LF_INVOKE(&cm->rtcd.loopfilter, normal_mb_h); + cm->lf_bh = LF_INVOKE(&cm->rtcd.loopfilter, normal_b_h); + } + else + { + cm->lf_mbv = LF_INVOKE(&cm->rtcd.loopfilter, simple_mb_v); + cm->lf_bv = LF_INVOKE(&cm->rtcd.loopfilter, simple_b_v); + cm->lf_mbh = LF_INVOKE(&cm->rtcd.loopfilter, simple_mb_h); + cm->lf_bh = LF_INVOKE(&cm->rtcd.loopfilter, simple_b_h); + } +} + +// Put vp8_init_loop_filter() in vp8dx_create_decompressor(). Only call vp8_frame_init_loop_filter() while decoding +// each frame. Check last_frame_type to skip the function most of times. +void vp8_frame_init_loop_filter(loop_filter_info *lfi, int frame_type) +{ + int HEVThresh; + int i, j; + + // For each possible value for the loop filter fill out a "loop_filter_info" entry. + for (i = 0; i <= MAX_LOOP_FILTER; i++) + { + int filt_lvl = i; + + if (frame_type == KEY_FRAME) + { + if (filt_lvl >= 40) + HEVThresh = 2; + else if (filt_lvl >= 15) + HEVThresh = 1; + else + HEVThresh = 0; + } + else + { + if (filt_lvl >= 40) + HEVThresh = 3; + else if (filt_lvl >= 20) + HEVThresh = 2; + else if (filt_lvl >= 15) + HEVThresh = 1; + else + HEVThresh = 0; + } + + for (j = 0; j < 16; j++) + { + //lfi[i].lim[j] = block_inside_limit; + //lfi[i].mbflim[j] = filt_lvl+yhedge_boost; + lfi[i].mbthr[j] = HEVThresh; + //lfi[i].flim[j] = filt_lvl; + lfi[i].thr[j] = HEVThresh; + //lfi[i].uvlim[j] = block_inside_limit; + //lfi[i].uvmbflim[j] = filt_lvl+uvhedge_boost; + lfi[i].uvmbthr[j] = HEVThresh; + //lfi[i].uvflim[j] = filt_lvl; + lfi[i].uvthr[j] = HEVThresh; + } + } +} + + +void vp8_adjust_mb_lf_value(MACROBLOCKD *mbd, int *filter_level) +{ + MB_MODE_INFO *mbmi = &mbd->mode_info_context->mbmi; + + if (mbd->mode_ref_lf_delta_enabled) + { + // Aplly delta for reference frame + *filter_level += mbd->ref_lf_deltas[mbmi->ref_frame]; + + // Apply delta for mode + if (mbmi->ref_frame == INTRA_FRAME) + { + // Only the split mode BPRED has a further special case + if (mbmi->mode == B_PRED) + *filter_level += mbd->mode_lf_deltas[0]; + } + else + { + // Zero motion mode + if (mbmi->mode == ZEROMV) + *filter_level += mbd->mode_lf_deltas[1]; + + // Split MB motion mode + else if (mbmi->mode == SPLITMV) + *filter_level += mbd->mode_lf_deltas[3]; + + // All other inter motion modes (Nearest, Near, New) + else + *filter_level += mbd->mode_lf_deltas[2]; + } + + // Range check + if (*filter_level > MAX_LOOP_FILTER) + *filter_level = MAX_LOOP_FILTER; + else if (*filter_level < 0) + *filter_level = 0; + } +} + + +void vp8_loop_filter_frame +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + loop_filter_info *lfi = cm->lf_info; + int frame_type = cm->frame_type; + + int mb_row; + int mb_col; + + + int baseline_filter_level[MAX_MB_SEGMENTS]; + int filter_level; + int alt_flt_enabled = mbd->segmentation_enabled; + + int i; + unsigned char *y_ptr, *u_ptr, *v_ptr; + + mbd->mode_info_context = cm->mi; // Point at base of Mb MODE_INFO list + + // Note the baseline filter values for each segment + if (alt_flt_enabled) + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + // Abs value + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + baseline_filter_level[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + // Delta Value + else + { + baseline_filter_level[i] = default_filt_lvl + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + baseline_filter_level[i] = (baseline_filter_level[i] >= 0) ? ((baseline_filter_level[i] <= MAX_LOOP_FILTER) ? baseline_filter_level[i] : MAX_LOOP_FILTER) : 0; // Clamp to valid range + } + } + } + else + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + baseline_filter_level[i] = default_filt_lvl; + } + + // Initialize the loop filter for this frame. + if ((cm->last_filter_type != cm->filter_type) || (cm->last_sharpness_level != cm->sharpness_level)) + vp8_init_loop_filter(cm); + else if (frame_type != cm->last_frame_type) + vp8_frame_init_loop_filter(lfi, frame_type); + + // Set up the buffer pointers + y_ptr = post->y_buffer; + u_ptr = post->u_buffer; + v_ptr = post->v_buffer; + + // vp8_filter each macro block + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int Segment = (alt_flt_enabled) ? mbd->mode_info_context->mbmi.segment_id : 0; + + filter_level = baseline_filter_level[Segment]; + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + // Apply any context driven MB level adjustment + vp8_adjust_mb_lf_value(mbd, &filter_level); + + if (filter_level) + { + if (mb_col > 0) + cm->lf_mbv(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bv(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + // don't apply across umv border + if (mb_row > 0) + cm->lf_mbh(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bh(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + } + + y_ptr += 16; + u_ptr += 8; + v_ptr += 8; + + mbd->mode_info_context++; // step to next MB + } + + y_ptr += post->y_stride * 16 - post->y_width; + u_ptr += post->uv_stride * 8 - post->uv_width; + v_ptr += post->uv_stride * 8 - post->uv_width; + + mbd->mode_info_context++; // Skip border mb + } +} + + +void vp8_loop_filter_frame_yonly +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl, + int sharpness_lvl +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + + int i; + unsigned char *y_ptr; + int mb_row; + int mb_col; + + loop_filter_info *lfi = cm->lf_info; + int baseline_filter_level[MAX_MB_SEGMENTS]; + int filter_level; + int alt_flt_enabled = mbd->segmentation_enabled; + int frame_type = cm->frame_type; + + (void) sharpness_lvl; + + //MODE_INFO * this_mb_mode_info = cm->mi; // Point at base of Mb MODE_INFO list + mbd->mode_info_context = cm->mi; // Point at base of Mb MODE_INFO list + + // Note the baseline filter values for each segment + if (alt_flt_enabled) + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + // Abs value + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + baseline_filter_level[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + // Delta Value + else + { + baseline_filter_level[i] = default_filt_lvl + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + baseline_filter_level[i] = (baseline_filter_level[i] >= 0) ? ((baseline_filter_level[i] <= MAX_LOOP_FILTER) ? baseline_filter_level[i] : MAX_LOOP_FILTER) : 0; // Clamp to valid range + } + } + } + else + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + baseline_filter_level[i] = default_filt_lvl; + } + + // Initialize the loop filter for this frame. + if ((cm->last_filter_type != cm->filter_type) || (cm->last_sharpness_level != cm->sharpness_level)) + vp8_init_loop_filter(cm); + else if (frame_type != cm->last_frame_type) + vp8_frame_init_loop_filter(lfi, frame_type); + + // Set up the buffer pointers + y_ptr = post->y_buffer; + + // vp8_filter each macro block + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int Segment = (alt_flt_enabled) ? mbd->mode_info_context->mbmi.segment_id : 0; + filter_level = baseline_filter_level[Segment]; + + // Apply any context driven MB level adjustment + vp8_adjust_mb_lf_value(mbd, &filter_level); + + if (filter_level) + { + if (mb_col > 0) + cm->lf_mbv(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bv(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + // don't apply across umv border + if (mb_row > 0) + cm->lf_mbh(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bh(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + } + + y_ptr += 16; + mbd->mode_info_context ++; // step to next MB + + } + + y_ptr += post->y_stride * 16 - post->y_width; + mbd->mode_info_context ++; // Skip border mb + } + +} + + +void vp8_loop_filter_partial_frame +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl, + int sharpness_lvl, + int Fraction +) +{ + YV12_BUFFER_CONFIG *post = cm->frame_to_show; + + int i; + unsigned char *y_ptr; + int mb_row; + int mb_col; + //int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + + int linestocopy; + + loop_filter_info *lfi = cm->lf_info; + int baseline_filter_level[MAX_MB_SEGMENTS]; + int filter_level; + int alt_flt_enabled = mbd->segmentation_enabled; + int frame_type = cm->frame_type; + + (void) sharpness_lvl; + + //MODE_INFO * this_mb_mode_info = cm->mi + (post->y_height>>5) * (mb_cols + 1); // Point at base of Mb MODE_INFO list + mbd->mode_info_context = cm->mi + (post->y_height >> 5) * (mb_cols + 1); // Point at base of Mb MODE_INFO list + + linestocopy = (post->y_height >> (4 + Fraction)); + + if (linestocopy < 1) + linestocopy = 1; + + linestocopy <<= 4; + + // Note the baseline filter values for each segment + if (alt_flt_enabled) + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + // Abs value + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + baseline_filter_level[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + // Delta Value + else + { + baseline_filter_level[i] = default_filt_lvl + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + baseline_filter_level[i] = (baseline_filter_level[i] >= 0) ? ((baseline_filter_level[i] <= MAX_LOOP_FILTER) ? baseline_filter_level[i] : MAX_LOOP_FILTER) : 0; // Clamp to valid range + } + } + } + else + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + baseline_filter_level[i] = default_filt_lvl; + } + + // Initialize the loop filter for this frame. + if ((cm->last_filter_type != cm->filter_type) || (cm->last_sharpness_level != cm->sharpness_level)) + vp8_init_loop_filter(cm); + else if (frame_type != cm->last_frame_type) + vp8_frame_init_loop_filter(lfi, frame_type); + + // Set up the buffer pointers + y_ptr = post->y_buffer + (post->y_height >> 5) * 16 * post->y_stride; + + // vp8_filter each macro block + for (mb_row = 0; mb_row<(linestocopy >> 4); mb_row++) + { + for (mb_col = 0; mb_col < mb_cols; mb_col++) + { + int Segment = (alt_flt_enabled) ? mbd->mode_info_context->mbmi.segment_id : 0; + filter_level = baseline_filter_level[Segment]; + + if (filter_level) + { + if (mb_col > 0) + cm->lf_mbv(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bv(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + cm->lf_mbh(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bh(y_ptr, 0, 0, post->y_stride, 0, &lfi[filter_level], 0); + } + + y_ptr += 16; + mbd->mode_info_context += 1; // step to next MB + } + + y_ptr += post->y_stride * 16 - post->y_width; + mbd->mode_info_context += 1; // Skip border mb + } +}
diff --git a/vp8/common/loopfilter.h b/vp8/common/loopfilter.h new file mode 100644 index 0000000..c6ce508 --- /dev/null +++ b/vp8/common/loopfilter.h
@@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef loopfilter_h +#define loopfilter_h + +#include "vpx_ports/mem.h" + +#define MAX_LOOP_FILTER 63 + +typedef enum +{ + NORMAL_LOOPFILTER = 0, + SIMPLE_LOOPFILTER = 1 +} LOOPFILTERTYPE; + +// FRK +// Need to align this structure so when it is declared and +// passed it can be loaded into vector registers. +// FRK +typedef struct +{ + DECLARE_ALIGNED(16, signed char, lim[16]); + DECLARE_ALIGNED(16, signed char, flim[16]); + DECLARE_ALIGNED(16, signed char, thr[16]); + DECLARE_ALIGNED(16, signed char, mbflim[16]); + DECLARE_ALIGNED(16, signed char, mbthr[16]); + DECLARE_ALIGNED(16, signed char, uvlim[16]); + DECLARE_ALIGNED(16, signed char, uvflim[16]); + DECLARE_ALIGNED(16, signed char, uvthr[16]); + DECLARE_ALIGNED(16, signed char, uvmbflim[16]); + DECLARE_ALIGNED(16, signed char, uvmbthr[16]); +} loop_filter_info; + + +#define prototype_loopfilter(sym) \ + void sym(unsigned char *src, int pitch, const signed char *flimit,\ + const signed char *limit, const signed char *thresh, int count) + +#define prototype_loopfilter_block(sym) \ + void sym(unsigned char *y, unsigned char *u, unsigned char *v,\ + int ystride, int uv_stride, loop_filter_info *lfi, int simpler) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/loopfilter_x86.h" +#endif + +#if ARCH_ARM +#include "arm/loopfilter_arm.h" +#endif + +#ifndef vp8_lf_normal_mb_v +#define vp8_lf_normal_mb_v vp8_loop_filter_mbv_c +#endif +extern prototype_loopfilter_block(vp8_lf_normal_mb_v); + +#ifndef vp8_lf_normal_b_v +#define vp8_lf_normal_b_v vp8_loop_filter_bv_c +#endif +extern prototype_loopfilter_block(vp8_lf_normal_b_v); + +#ifndef vp8_lf_normal_mb_h +#define vp8_lf_normal_mb_h vp8_loop_filter_mbh_c +#endif +extern prototype_loopfilter_block(vp8_lf_normal_mb_h); + +#ifndef vp8_lf_normal_b_h +#define vp8_lf_normal_b_h vp8_loop_filter_bh_c +#endif +extern prototype_loopfilter_block(vp8_lf_normal_b_h); + + +#ifndef vp8_lf_simple_mb_v +#define vp8_lf_simple_mb_v vp8_loop_filter_mbvs_c +#endif +extern prototype_loopfilter_block(vp8_lf_simple_mb_v); + +#ifndef vp8_lf_simple_b_v +#define vp8_lf_simple_b_v vp8_loop_filter_bvs_c +#endif +extern prototype_loopfilter_block(vp8_lf_simple_b_v); + +#ifndef vp8_lf_simple_mb_h +#define vp8_lf_simple_mb_h vp8_loop_filter_mbhs_c +#endif +extern prototype_loopfilter_block(vp8_lf_simple_mb_h); + +#ifndef vp8_lf_simple_b_h +#define vp8_lf_simple_b_h vp8_loop_filter_bhs_c +#endif +extern prototype_loopfilter_block(vp8_lf_simple_b_h); + +typedef prototype_loopfilter_block((*vp8_lf_block_fn_t)); +typedef struct +{ + vp8_lf_block_fn_t normal_mb_v; + vp8_lf_block_fn_t normal_b_v; + vp8_lf_block_fn_t normal_mb_h; + vp8_lf_block_fn_t normal_b_h; + vp8_lf_block_fn_t simple_mb_v; + vp8_lf_block_fn_t simple_b_v; + vp8_lf_block_fn_t simple_mb_h; + vp8_lf_block_fn_t simple_b_h; +} vp8_loopfilter_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define LF_INVOKE(ctx,fn) (ctx)->fn +#else +#define LF_INVOKE(ctx,fn) vp8_lf_##fn +#endif + + +#endif
diff --git a/vp8/common/loopfilter_filters.c b/vp8/common/loopfilter_filters.c new file mode 100644 index 0000000..7d16e48 --- /dev/null +++ b/vp8/common/loopfilter_filters.c
@@ -0,0 +1,368 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> +#include "loopfilter.h" +#include "onyxc_int.h" + + +#define NEW_LOOPFILTER_MASK + +typedef unsigned char uc; + +__inline signed char vp8_signed_char_clamp(int t) +{ + t = (t < -128 ? -128 : t); + t = (t > 127 ? 127 : t); + return (signed char) t; +} + + +// should we apply any filter at all ( 11111111 yes, 00000000 no) +__inline signed char vp8_filter_mask(signed char limit, signed char flimit, + uc p3, uc p2, uc p1, uc p0, uc q0, uc q1, uc q2, uc q3) +{ + signed char mask = 0; + mask |= (abs(p3 - p2) > limit) * -1; + mask |= (abs(p2 - p1) > limit) * -1; + mask |= (abs(p1 - p0) > limit) * -1; + mask |= (abs(q1 - q0) > limit) * -1; + mask |= (abs(q2 - q1) > limit) * -1; + mask |= (abs(q3 - q2) > limit) * -1; +#ifndef NEW_LOOPFILTER_MASK + mask |= (abs(p0 - q0) > flimit) * -1; +#else + mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 > flimit * 2 + limit) * -1; +#endif + mask = ~mask; + return mask; +} + +// is there high variance internal edge ( 11111111 yes, 00000000 no) +__inline signed char vp8_hevmask(signed char thresh, uc p1, uc p0, uc q0, uc q1) +{ + signed char hev = 0; + hev |= (abs(p1 - p0) > thresh) * -1; + hev |= (abs(q1 - q0) > thresh) * -1; + return hev; +} + +__inline void vp8_filter(signed char mask, signed char hev, uc *op1, uc *op0, uc *oq0, uc *oq1) + +{ + signed char ps0, qs0; + signed char ps1, qs1; + signed char vp8_filter, Filter1, Filter2; + signed char u; + + ps1 = (signed char) * op1 ^ 0x80; + ps0 = (signed char) * op0 ^ 0x80; + qs0 = (signed char) * oq0 ^ 0x80; + qs1 = (signed char) * oq1 ^ 0x80; + + // add outer taps if we have high edge variance + vp8_filter = vp8_signed_char_clamp(ps1 - qs1); + vp8_filter &= hev; + + // inner taps + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); + vp8_filter &= mask; + + // save bottom 3 bits so that we round one side +4 and the other +3 + // if it equals 4 we'll set to adjust by -1 to account for the fact + // we'd round 3 the other way + Filter1 = vp8_signed_char_clamp(vp8_filter + 4); + Filter2 = vp8_signed_char_clamp(vp8_filter + 3); + Filter1 >>= 3; + Filter2 >>= 3; + u = vp8_signed_char_clamp(qs0 - Filter1); + *oq0 = u ^ 0x80; + u = vp8_signed_char_clamp(ps0 + Filter2); + *op0 = u ^ 0x80; + vp8_filter = Filter1; + + // outer tap adjustments + vp8_filter += 1; + vp8_filter >>= 1; + vp8_filter &= ~hev; + + u = vp8_signed_char_clamp(qs1 - vp8_filter); + *oq1 = u ^ 0x80; + u = vp8_signed_char_clamp(ps1 + vp8_filter); + *op1 = u ^ 0x80; + +} +void vp8_loop_filter_horizontal_edge_c +( + unsigned char *s, + int p, //pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + int hev = 0; // high edge variance + signed char mask = 0; + int i = 0; + + // loop filter designed to work using chars so that we can make maximum use + // of 8 bit simd instructions. + do + { + mask = vp8_filter_mask(limit[i], flimit[i], + s[-4*p], s[-3*p], s[-2*p], s[-1*p], + s[0*p], s[1*p], s[2*p], s[3*p]); + + hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]); + + vp8_filter(mask, hev, s - 2 * p, s - 1 * p, s, s + 1 * p); + + ++s; + } + while (++i < count * 8); +} + +void vp8_loop_filter_vertical_edge_c +( + unsigned char *s, + int p, + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + int hev = 0; // high edge variance + signed char mask = 0; + int i = 0; + + // loop filter designed to work using chars so that we can make maximum use + // of 8 bit simd instructions. + do + { + mask = vp8_filter_mask(limit[i], flimit[i], + s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + + hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]); + + vp8_filter(mask, hev, s - 2, s - 1, s, s + 1); + + s += p; + } + while (++i < count * 8); +} + +__inline void vp8_mbfilter(signed char mask, signed char hev, + uc *op2, uc *op1, uc *op0, uc *oq0, uc *oq1, uc *oq2) +{ + signed char s, u; + signed char vp8_filter, Filter1, Filter2; + signed char ps2 = (signed char) * op2 ^ 0x80; + signed char ps1 = (signed char) * op1 ^ 0x80; + signed char ps0 = (signed char) * op0 ^ 0x80; + signed char qs0 = (signed char) * oq0 ^ 0x80; + signed char qs1 = (signed char) * oq1 ^ 0x80; + signed char qs2 = (signed char) * oq2 ^ 0x80; + + // add outer taps if we have high edge variance + vp8_filter = vp8_signed_char_clamp(ps1 - qs1); + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (qs0 - ps0)); + vp8_filter &= mask; + + Filter2 = vp8_filter; + Filter2 &= hev; + + // save bottom 3 bits so that we round one side +4 and the other +3 + Filter1 = vp8_signed_char_clamp(Filter2 + 4); + Filter2 = vp8_signed_char_clamp(Filter2 + 3); + Filter1 >>= 3; + Filter2 >>= 3; + qs0 = vp8_signed_char_clamp(qs0 - Filter1); + ps0 = vp8_signed_char_clamp(ps0 + Filter2); + + + // only apply wider filter if not high edge variance + vp8_filter &= ~hev; + Filter2 = vp8_filter; + + // roughly 3/7th difference across boundary + u = vp8_signed_char_clamp((63 + Filter2 * 27) >> 7); + s = vp8_signed_char_clamp(qs0 - u); + *oq0 = s ^ 0x80; + s = vp8_signed_char_clamp(ps0 + u); + *op0 = s ^ 0x80; + + // roughly 2/7th difference across boundary + u = vp8_signed_char_clamp((63 + Filter2 * 18) >> 7); + s = vp8_signed_char_clamp(qs1 - u); + *oq1 = s ^ 0x80; + s = vp8_signed_char_clamp(ps1 + u); + *op1 = s ^ 0x80; + + // roughly 1/7th difference across boundary + u = vp8_signed_char_clamp((63 + Filter2 * 9) >> 7); + s = vp8_signed_char_clamp(qs2 - u); + *oq2 = s ^ 0x80; + s = vp8_signed_char_clamp(ps2 + u); + *op2 = s ^ 0x80; +} + +void vp8_mbloop_filter_horizontal_edge_c +( + unsigned char *s, + int p, + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + signed char hev = 0; // high edge variance + signed char mask = 0; + int i = 0; + + // loop filter designed to work using chars so that we can make maximum use + // of 8 bit simd instructions. + do + { + + mask = vp8_filter_mask(limit[i], flimit[i], + s[-4*p], s[-3*p], s[-2*p], s[-1*p], + s[0*p], s[1*p], s[2*p], s[3*p]); + + hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]); + + vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p); + + ++s; + } + while (++i < count * 8); + +} + + +void vp8_mbloop_filter_vertical_edge_c +( + unsigned char *s, + int p, + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + signed char hev = 0; // high edge variance + signed char mask = 0; + int i = 0; + + do + { + + mask = vp8_filter_mask(limit[i], flimit[i], + s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]); + + hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]); + + vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2); + + s += p; + } + while (++i < count * 8); + +} + +// should we apply any filter at all ( 11111111 yes, 00000000 no) +__inline signed char vp8_simple_filter_mask(signed char limit, signed char flimit, uc p1, uc p0, uc q0, uc q1) +{ +// Why does this cause problems for win32? +// error C2143: syntax error : missing ';' before 'type' +// (void) limit; +#ifndef NEW_LOOPFILTER_MASK + signed char mask = (abs(p0 - q0) <= flimit) * -1; +#else + signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2 <= flimit * 2 + limit) * -1; +#endif + return mask; +} + +__inline void vp8_simple_filter(signed char mask, uc *op1, uc *op0, uc *oq0, uc *oq1) +{ + signed char vp8_filter, Filter1, Filter2; + signed char p1 = (signed char) * op1 ^ 0x80; + signed char p0 = (signed char) * op0 ^ 0x80; + signed char q0 = (signed char) * oq0 ^ 0x80; + signed char q1 = (signed char) * oq1 ^ 0x80; + signed char u; + + vp8_filter = vp8_signed_char_clamp(p1 - q1); + vp8_filter = vp8_signed_char_clamp(vp8_filter + 3 * (q0 - p0)); + vp8_filter &= mask; + + // save bottom 3 bits so that we round one side +4 and the other +3 + Filter1 = vp8_signed_char_clamp(vp8_filter + 4); + Filter1 >>= 3; + u = vp8_signed_char_clamp(q0 - Filter1); + *oq0 = u ^ 0x80; + + Filter2 = vp8_signed_char_clamp(vp8_filter + 3); + Filter2 >>= 3; + u = vp8_signed_char_clamp(p0 + Filter2); + *op0 = u ^ 0x80; +} + +void vp8_loop_filter_simple_horizontal_edge_c +( + unsigned char *s, + int p, + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + signed char mask = 0; + int i = 0; + (void) thresh; + + do + { + //mask = vp8_simple_filter_mask( limit[i], flimit[i],s[-1*p],s[0*p]); + mask = vp8_simple_filter_mask(limit[i], flimit[i], s[-2*p], s[-1*p], s[0*p], s[1*p]); + vp8_simple_filter(mask, s - 2 * p, s - 1 * p, s, s + 1 * p); + ++s; + } + while (++i < count * 8); +} + +void vp8_loop_filter_simple_vertical_edge_c +( + unsigned char *s, + int p, + const signed char *flimit, + const signed char *limit, + const signed char *thresh, + int count +) +{ + signed char mask = 0; + int i = 0; + (void) thresh; + + do + { + //mask = vp8_simple_filter_mask( limit[i], flimit[i],s[-1],s[0]); + mask = vp8_simple_filter_mask(limit[i], flimit[i], s[-2], s[-1], s[0], s[1]); + vp8_simple_filter(mask, s - 2, s - 1, s, s + 1); + s += p; + } + while (++i < count * 8); + +}
diff --git a/vp8/common/mac_specs.h b/vp8/common/mac_specs.h new file mode 100644 index 0000000..97bffc7 --- /dev/null +++ b/vp8/common/mac_specs.h
@@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if !defined(_mac_specs_h) +#define _mac_specs_h + + +#if defined(__cplusplus) +extern "C" { +#endif + + extern unsigned int vp8_read_tsc(); + + extern unsigned int vp8_get_processor_freq(); + + extern unsigned int vpx_has_altivec(); + +#if defined(__cplusplus) +} +#endif + + +#endif
diff --git a/vp8/common/mbpitch.c b/vp8/common/mbpitch.c new file mode 100644 index 0000000..a7e0ce9 --- /dev/null +++ b/vp8/common/mbpitch.c
@@ -0,0 +1,128 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "blockd.h" + +typedef enum +{ + PRED = 0, + DEST = 1, +} BLOCKSET; + +void vp8_setup_block +( + BLOCKD *b, + int mv_stride, + unsigned char **base, + int Stride, + int offset, + BLOCKSET bs +) +{ + + if (bs == DEST) + { + b->dst_stride = Stride; + b->dst = offset; + b->base_dst = base; + } + else + { + b->pre_stride = Stride; + b->pre = offset; + b->base_pre = base; + } + +} + +void vp8_setup_macroblock(MACROBLOCKD *x, BLOCKSET bs) +{ + int block; + + unsigned char **y, **u, **v; + + if (bs == DEST) + { + y = &x->dst.y_buffer; + u = &x->dst.u_buffer; + v = &x->dst.v_buffer; + } + else + { + y = &x->pre.y_buffer; + u = &x->pre.u_buffer; + v = &x->pre.v_buffer; + } + + for (block = 0; block < 16; block++) // y blocks + { + vp8_setup_block(&x->block[block], x->dst.y_stride, y, x->dst.y_stride, + (block >> 2) * 4 * x->dst.y_stride + (block & 3) * 4, bs); + } + + for (block = 16; block < 20; block++) // U and V blocks + { + vp8_setup_block(&x->block[block], x->dst.uv_stride, u, x->dst.uv_stride, + ((block - 16) >> 1) * 4 * x->dst.uv_stride + (block & 1) * 4, bs); + + vp8_setup_block(&x->block[block+4], x->dst.uv_stride, v, x->dst.uv_stride, + ((block - 16) >> 1) * 4 * x->dst.uv_stride + (block & 1) * 4, bs); + } +} + +void vp8_setup_block_dptrs(MACROBLOCKD *x) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + x->block[r*4+c].diff = &x->diff[r * 4 * 16 + c * 4]; + x->block[r*4+c].predictor = x->predictor + r * 4 * 16 + c * 4; + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[16+r*2+c].diff = &x->diff[256 + r * 4 * 8 + c * 4]; + x->block[16+r*2+c].predictor = x->predictor + 256 + r * 4 * 8 + c * 4; + + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[20+r*2+c].diff = &x->diff[320+ r * 4 * 8 + c * 4]; + x->block[20+r*2+c].predictor = x->predictor + 320 + r * 4 * 8 + c * 4; + + } + } + + x->block[24].diff = &x->diff[384]; + + for (r = 0; r < 25; r++) + { + x->block[r].qcoeff = x->qcoeff + r * 16; + x->block[r].dqcoeff = x->dqcoeff + r * 16; + } +} + +void vp8_build_block_doffsets(MACROBLOCKD *x) +{ + + // handle the destination pitch features + vp8_setup_macroblock(x, DEST); + vp8_setup_macroblock(x, PRED); +}
diff --git a/vp8/common/modecont.c b/vp8/common/modecont.c new file mode 100644 index 0000000..9301a25 --- /dev/null +++ b/vp8/common/modecont.c
@@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "entropy.h" + +const int vp8_mode_contexts[6][4] = +{ + { + // 0 + 7, 1, 1, 143, + }, + { + // 1 + 14, 18, 14, 107, + }, + { + // 2 + 135, 64, 57, 68, + }, + { + // 3 + 60, 56, 128, 65, + }, + { + // 4 + 159, 134, 128, 34, + }, + { + // 5 + 234, 188, 128, 28, + }, +};
diff --git a/vp8/common/modecont.h b/vp8/common/modecont.h new file mode 100644 index 0000000..0c57651 --- /dev/null +++ b/vp8/common/modecont.h
@@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_MODECONT_H +#define __INC_MODECONT_H + +extern const int vp8_mode_contexts[6][4]; + +#endif
diff --git a/vp8/common/modecontext.c b/vp8/common/modecontext.c new file mode 100644 index 0000000..ceee74c --- /dev/null +++ b/vp8/common/modecontext.c
@@ -0,0 +1,145 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "entropymode.h" + +const unsigned int vp8_kf_default_bmode_counts [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES] = +{ + { + //Above Mode : 0 + { 43438, 2195, 470, 316, 615, 171, 217, 412, 124, 160, }, // left_mode 0 + { 5722, 2751, 296, 291, 81, 68, 80, 101, 100, 170, }, // left_mode 1 + { 1629, 201, 307, 25, 47, 16, 34, 72, 19, 28, }, // left_mode 2 + { 332, 266, 36, 500, 20, 65, 23, 14, 154, 106, }, // left_mode 3 + { 450, 97, 10, 24, 117, 10, 2, 12, 8, 71, }, // left_mode 4 + { 384, 49, 29, 44, 12, 162, 51, 5, 87, 42, }, // left_mode 5 + { 495, 53, 157, 27, 14, 57, 180, 17, 17, 34, }, // left_mode 6 + { 695, 64, 62, 9, 27, 5, 3, 147, 10, 26, }, // left_mode 7 + { 230, 54, 20, 124, 16, 125, 29, 12, 283, 37, }, // left_mode 8 + { 260, 87, 21, 120, 32, 16, 33, 16, 33, 203, }, // left_mode 9 + }, + { + //Above Mode : 1 + { 3934, 2573, 355, 137, 128, 87, 133, 117, 37, 27, }, // left_mode 0 + { 1036, 1929, 278, 135, 27, 37, 48, 55, 41, 91, }, // left_mode 1 + { 223, 256, 253, 15, 13, 9, 28, 64, 3, 3, }, // left_mode 2 + { 120, 129, 17, 316, 15, 11, 9, 4, 53, 74, }, // left_mode 3 + { 129, 58, 6, 11, 38, 2, 0, 5, 2, 67, }, // left_mode 4 + { 53, 22, 11, 16, 8, 26, 14, 3, 19, 12, }, // left_mode 5 + { 59, 26, 61, 11, 4, 9, 35, 13, 8, 8, }, // left_mode 6 + { 101, 52, 40, 8, 5, 2, 8, 59, 2, 20, }, // left_mode 7 + { 48, 34, 10, 52, 8, 15, 6, 6, 63, 20, }, // left_mode 8 + { 96, 48, 22, 63, 11, 14, 5, 8, 9, 96, }, // left_mode 9 + }, + { + //Above Mode : 2 + { 709, 461, 506, 36, 27, 33, 151, 98, 24, 6, }, // left_mode 0 + { 201, 375, 442, 27, 13, 8, 46, 58, 6, 19, }, // left_mode 1 + { 122, 140, 417, 4, 13, 3, 33, 59, 4, 2, }, // left_mode 2 + { 36, 17, 22, 16, 6, 8, 12, 17, 9, 21, }, // left_mode 3 + { 51, 15, 7, 1, 14, 0, 4, 5, 3, 22, }, // left_mode 4 + { 18, 11, 30, 9, 7, 20, 11, 5, 2, 6, }, // left_mode 5 + { 38, 21, 103, 9, 4, 12, 79, 13, 2, 5, }, // left_mode 6 + { 64, 17, 66, 2, 12, 4, 2, 65, 4, 5, }, // left_mode 7 + { 14, 7, 7, 16, 3, 11, 4, 13, 15, 16, }, // left_mode 8 + { 36, 8, 32, 9, 9, 4, 14, 7, 6, 24, }, // left_mode 9 + }, + { + //Above Mode : 3 + { 1340, 173, 36, 119, 30, 10, 13, 10, 20, 26, }, // left_mode 0 + { 156, 293, 26, 108, 5, 16, 2, 4, 23, 30, }, // left_mode 1 + { 60, 34, 13, 7, 3, 3, 0, 8, 4, 5, }, // left_mode 2 + { 72, 64, 1, 235, 3, 9, 2, 7, 28, 38, }, // left_mode 3 + { 29, 14, 1, 3, 5, 0, 2, 2, 5, 13, }, // left_mode 4 + { 22, 7, 4, 11, 2, 5, 1, 2, 6, 4, }, // left_mode 5 + { 18, 14, 5, 6, 4, 3, 14, 0, 9, 2, }, // left_mode 6 + { 41, 10, 7, 1, 2, 0, 0, 10, 2, 1, }, // left_mode 7 + { 23, 19, 2, 33, 1, 5, 2, 0, 51, 8, }, // left_mode 8 + { 33, 26, 7, 53, 3, 9, 3, 3, 9, 19, }, // left_mode 9 + }, + { + //Above Mode : 4 + { 410, 165, 43, 31, 66, 15, 30, 54, 8, 17, }, // left_mode 0 + { 115, 64, 27, 18, 30, 7, 11, 15, 4, 19, }, // left_mode 1 + { 31, 23, 25, 1, 7, 2, 2, 10, 0, 5, }, // left_mode 2 + { 17, 4, 1, 6, 8, 2, 7, 5, 5, 21, }, // left_mode 3 + { 120, 12, 1, 2, 83, 3, 0, 4, 1, 40, }, // left_mode 4 + { 4, 3, 1, 2, 1, 2, 5, 0, 3, 6, }, // left_mode 5 + { 10, 2, 13, 6, 6, 6, 8, 2, 4, 5, }, // left_mode 6 + { 58, 10, 5, 1, 28, 1, 1, 33, 1, 9, }, // left_mode 7 + { 8, 2, 1, 4, 2, 5, 1, 1, 2, 10, }, // left_mode 8 + { 76, 7, 5, 7, 18, 2, 2, 0, 5, 45, }, // left_mode 9 + }, + { + //Above Mode : 5 + { 444, 46, 47, 20, 14, 110, 60, 14, 60, 7, }, // left_mode 0 + { 59, 57, 25, 18, 3, 17, 21, 6, 14, 6, }, // left_mode 1 + { 24, 17, 20, 6, 4, 13, 7, 2, 3, 2, }, // left_mode 2 + { 13, 11, 5, 14, 4, 9, 2, 4, 15, 7, }, // left_mode 3 + { 8, 5, 2, 1, 4, 0, 1, 1, 2, 12, }, // left_mode 4 + { 19, 5, 5, 7, 4, 40, 6, 3, 10, 4, }, // left_mode 5 + { 16, 5, 9, 1, 1, 16, 26, 2, 10, 4, }, // left_mode 6 + { 11, 4, 8, 1, 1, 4, 4, 5, 4, 1, }, // left_mode 7 + { 15, 1, 3, 7, 3, 21, 7, 1, 34, 5, }, // left_mode 8 + { 18, 5, 1, 3, 4, 3, 7, 1, 2, 9, }, // left_mode 9 + }, + { + //Above Mode : 6 + { 476, 149, 94, 13, 14, 77, 291, 27, 23, 3, }, // left_mode 0 + { 79, 83, 42, 14, 2, 12, 63, 2, 4, 14, }, // left_mode 1 + { 43, 36, 55, 1, 3, 8, 42, 11, 5, 1, }, // left_mode 2 + { 9, 9, 6, 16, 1, 5, 6, 3, 11, 10, }, // left_mode 3 + { 10, 3, 1, 3, 10, 1, 0, 1, 1, 4, }, // left_mode 4 + { 14, 6, 15, 5, 1, 20, 25, 2, 5, 0, }, // left_mode 5 + { 28, 7, 51, 1, 0, 8, 127, 6, 2, 5, }, // left_mode 6 + { 13, 3, 3, 2, 3, 1, 2, 8, 1, 2, }, // left_mode 7 + { 10, 3, 3, 3, 3, 8, 2, 2, 9, 3, }, // left_mode 8 + { 13, 7, 11, 4, 0, 4, 6, 2, 5, 8, }, // left_mode 9 + }, + { + //Above Mode : 7 + { 376, 135, 119, 6, 32, 8, 31, 224, 9, 3, }, // left_mode 0 + { 93, 60, 54, 6, 13, 7, 8, 92, 2, 12, }, // left_mode 1 + { 74, 36, 84, 0, 3, 2, 9, 67, 2, 1, }, // left_mode 2 + { 19, 4, 4, 8, 8, 2, 4, 7, 6, 16, }, // left_mode 3 + { 51, 7, 4, 1, 77, 3, 0, 14, 1, 15, }, // left_mode 4 + { 7, 7, 5, 7, 4, 7, 4, 5, 0, 3, }, // left_mode 5 + { 18, 2, 19, 2, 2, 4, 12, 11, 1, 2, }, // left_mode 6 + { 129, 6, 27, 1, 21, 3, 0, 189, 0, 6, }, // left_mode 7 + { 9, 1, 2, 8, 3, 7, 0, 5, 3, 3, }, // left_mode 8 + { 20, 4, 5, 10, 4, 2, 7, 17, 3, 16, }, // left_mode 9 + }, + { + //Above Mode : 8 + { 617, 68, 34, 79, 11, 27, 25, 14, 75, 13, }, // left_mode 0 + { 51, 82, 21, 26, 6, 12, 13, 1, 26, 16, }, // left_mode 1 + { 29, 9, 12, 11, 3, 7, 1, 10, 2, 2, }, // left_mode 2 + { 17, 19, 11, 74, 4, 3, 2, 0, 58, 13, }, // left_mode 3 + { 10, 1, 1, 3, 4, 1, 0, 2, 1, 8, }, // left_mode 4 + { 14, 4, 5, 5, 1, 13, 2, 0, 27, 8, }, // left_mode 5 + { 10, 3, 5, 4, 1, 7, 6, 4, 5, 1, }, // left_mode 6 + { 10, 2, 6, 2, 1, 1, 1, 4, 2, 1, }, // left_mode 7 + { 14, 8, 5, 23, 2, 12, 6, 2, 117, 5, }, // left_mode 8 + { 9, 6, 2, 19, 1, 6, 3, 2, 9, 9, }, // left_mode 9 + }, + { + //Above Mode : 9 + { 680, 73, 22, 38, 42, 5, 11, 9, 6, 28, }, // left_mode 0 + { 113, 112, 21, 22, 10, 2, 8, 4, 6, 42, }, // left_mode 1 + { 44, 20, 24, 6, 5, 4, 3, 3, 1, 2, }, // left_mode 2 + { 40, 23, 7, 71, 5, 2, 4, 1, 7, 22, }, // left_mode 3 + { 85, 9, 4, 4, 17, 2, 0, 3, 2, 23, }, // left_mode 4 + { 13, 4, 2, 6, 1, 7, 0, 1, 7, 6, }, // left_mode 5 + { 26, 6, 8, 3, 2, 3, 8, 1, 5, 4, }, // left_mode 6 + { 54, 8, 9, 6, 7, 0, 1, 11, 1, 3, }, // left_mode 7 + { 9, 10, 4, 13, 2, 5, 4, 2, 14, 8, }, // left_mode 8 + { 92, 9, 5, 19, 15, 3, 3, 1, 6, 58, }, // left_mode 9 + }, +};
diff --git a/vp8/common/mv.h b/vp8/common/mv.h new file mode 100644 index 0000000..3d84181 --- /dev/null +++ b/vp8/common/mv.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_MV_H +#define __INC_MV_H + +typedef struct +{ + short row; + short col; +} MV; + +#endif
diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h new file mode 100644 index 0000000..b66c400 --- /dev/null +++ b/vp8/common/onyx.h
@@ -0,0 +1,222 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_VP8_H +#define __INC_VP8_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vpx_codec/internal/vpx_codec_internal.h" +#include "vpx_scale/yv12config.h" +#include "type_aliases.h" +#include "ppflags.h" + typedef int *VP8_PTR; + + /* Create/destroy static data structures. */ + + typedef enum + { + NORMAL = 0, + FOURFIVE = 1, + THREEFIVE = 2, + ONETWO = 3 + + } VPX_SCALING; + + typedef enum + { + VP8_LAST_FLAG = 1, + VP8_GOLD_FLAG = 2, + VP8_ALT_FLAG = 4 + } VP8_REFFRAME; + + + typedef enum + { + USAGE_STREAM_FROM_SERVER = 0x0, + USAGE_LOCAL_FILE_PLAYBACK = 0x1 + } END_USAGE; + + + typedef enum + { + MODE_REALTIME = 0x0, + MODE_GOODQUALITY = 0x1, + MODE_BESTQUALITY = 0x2, + MODE_FIRSTPASS = 0x3, + MODE_SECONDPASS = 0x4, + MODE_SECONDPASS_BEST = 0x5, + } MODE; + + typedef enum + { + FRAMEFLAGS_KEY = 1, + FRAMEFLAGS_GOLDEN = 2, + FRAMEFLAGS_ALTREF = 4, + } FRAMETYPE_FLAGS; + + +#include <assert.h> + static __inline void Scale2Ratio(int mode, int *hr, int *hs) + { + switch (mode) + { + case NORMAL: + *hr = 1; + *hs = 1; + break; + case FOURFIVE: + *hr = 4; + *hs = 5; + break; + case THREEFIVE: + *hr = 3; + *hs = 5; + break; + case ONETWO: + *hr = 1; + *hs = 2; + break; + default: + *hr = 1; + *hs = 1; + assert(0); + break; + } + } + + typedef struct + { + int Version; // 4 versions of bitstream defined 0 best quality/slowest decode, 3 lowest quality/fastest decode + int Width; // width of data passed to the compressor + int Height; // height of data passed to the compressor + double frame_rate; // set to passed in framerate + int target_bandwidth; // bandwidth to be used in kilobits per second + + int noise_sensitivity; // parameter used for applying pre processing blur: recommendation 0 + int Sharpness; // parameter used for sharpening output: recommendation 0: + int cpu_used; + + // mode -> + //(0)=Realtime/Live Encoding. This mode is optimized for realtim encoding (for example, capturing + // a television signal or feed from a live camera). ( speed setting controls how fast ) + //(1)=Good Quality Fast Encoding. The encoder balances quality with the amount of time it takes to + // encode the output. ( speed setting controls how fast ) + //(2)=One Pass - Best Quality. The encoder places priority on the quality of the output over encoding + // speed. The output is compressed at the highest possible quality. This option takes the longest + // amount of time to encode. ( speed setting ignored ) + //(3)=Two Pass - First Pass. The encoder generates a file of statistics for use in the second encoding + // pass. ( speed setting controls how fast ) + //(4)=Two Pass - Second Pass. The encoder uses the statistics that were generated in the first encoding + // pass to create the compressed output. ( speed setting controls how fast ) + //(5)=Two Pass - Second Pass Best. The encoder uses the statistics that were generated in the first + // encoding pass to create the compressed output using the highest possible quality, and taking a + // longer amount of time to encode.. ( speed setting ignored ) + int Mode; // + + // Key Framing Operations + int auto_key; // automatically detect cut scenes and set the keyframes + int key_freq; // maximum distance to key frame. + + int allow_lag; // allow lagged compression (if 0 lagin frames is ignored) + int lag_in_frames; // how many frames lag before we start encoding + + //---------------------------------------------------------------- + // DATARATE CONTROL OPTIONS + + int end_usage; // vbr or cbr + + // shoot to keep buffer full at all times by undershooting a bit 95 recommended + int under_shoot_pct; + + // buffering parameters + int starting_buffer_level; // in seconds + int optimal_buffer_level; + int maximum_buffer_size; + + // controlling quality + int fixed_q; + int worst_allowed_q; + int best_allowed_q; + + // allow internal resizing ( currently disabled in the build !!!!!) + int allow_spatial_resampling; + int resample_down_water_mark; + int resample_up_water_mark; + + // allow internal frame rate alterations + int allow_df; + int drop_frames_water_mark; + + // two pass datarate control + int two_pass_vbrbias; // two pass datarate control tweaks + int two_pass_vbrmin_section; + int two_pass_vbrmax_section; + // END DATARATE CONTROL OPTIONS + //---------------------------------------------------------------- + + + // these parameters aren't to be used in final build don't use!!! + int play_alternate; + int alt_freq; + int alt_q; + int key_q; + int gold_q; + + + int multi_threaded; // how many threads to run the encoder on + int token_partitions; // how many token partitions to create for multi core decoding + int encode_breakout; // early breakout encode threshold : for video conf recommend 800 + + int error_resilient_mode; // if running over udp networks provides decodable frames after a + // dropped packet + + int arnr_max_frames; + int arnr_strength ; + int arnr_type ; + + + struct vpx_fixed_buf two_pass_stats_in; + struct vpx_codec_pkt_list *output_pkt_list; + } VP8_CONFIG; + + + void vp8_initialize(); + + VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf); + void vp8_remove_compressor(VP8_PTR *comp); + + void vp8_init_config(VP8_PTR onyx, VP8_CONFIG *oxcf); + void vp8_change_config(VP8_PTR onyx, VP8_CONFIG *oxcf); + +// receive a frames worth of data caller can assume that a copy of this frame is made +// and not just a copy of the pointer.. + int vp8_receive_raw_frame(VP8_PTR comp, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, INT64 time_stamp, INT64 end_time_stamp); + int vp8_get_compressed_data(VP8_PTR comp, unsigned int *frame_flags, unsigned long *size, unsigned char *dest, INT64 *time_stamp, INT64 *time_end, int flush); + int vp8_get_preview_raw_frame(VP8_PTR comp, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags); + + int vp8_use_as_reference(VP8_PTR comp, int ref_frame_flags); + int vp8_update_reference(VP8_PTR comp, int ref_frame_flags); + int vp8_get_reference(VP8_PTR comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + int vp8_set_reference(VP8_PTR comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + int vp8_update_entropy(VP8_PTR comp, int update); + int vp8_set_roimap(VP8_PTR comp, unsigned char *map, unsigned int rows, unsigned int cols, int delta_q[4], int delta_lf[4], unsigned int threshold[4]); + int vp8_set_active_map(VP8_PTR comp, unsigned char *map, unsigned int rows, unsigned int cols); + int vp8_set_internal_size(VP8_PTR comp, VPX_SCALING horiz_mode, VPX_SCALING vert_mode); + int vp8_get_quantizer(VP8_PTR c); + +#ifdef __cplusplus +} +#endif + +#endif
diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h new file mode 100644 index 0000000..a40ffb9 --- /dev/null +++ b/vp8/common/onyxc_int.h
@@ -0,0 +1,205 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_VP8C_INT_H +#define __INC_VP8C_INT_H + +#include "vpx_ports/config.h" +#include "vpx_codec/internal/vpx_codec_internal.h" +#include "loopfilter.h" +#include "entropymv.h" +#include "entropy.h" +#include "idct.h" +#include "recon.h" +#include "postproc.h" + +//#ifdef PACKET_TESTING +#include "header.h" +//#endif + +/* Create/destroy static data structures. */ + +void vp8_initialize_common(void); + +#define MINQ 0 +#define MAXQ 127 +#define QINDEX_RANGE (MAXQ + 1) + + +typedef struct frame_contexts +{ + vp8_prob bmode_prob [VP8_BINTRAMODES-1]; + vp8_prob ymode_prob [VP8_YMODES-1]; /* interframe intra mode probs */ + vp8_prob uv_mode_prob [VP8_UV_MODES-1]; + vp8_prob sub_mv_ref_prob [VP8_SUBMVREFS-1]; + vp8_prob coef_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1]; + MV_CONTEXT mvc[2]; + MV_CONTEXT pre_mvc[2]; //not to caculate the mvcost for the frame if mvc doesn't change. +} FRAME_CONTEXT; + +typedef enum +{ + ONE_PARTITION = 0, + TWO_PARTITION = 1, + FOUR_PARTITION = 2, + EIGHT_PARTITION = 3 +} TOKEN_PARTITION; + +typedef enum +{ + RECON_CLAMP_REQUIRED = 0, + RECON_CLAMP_NOTREQUIRED = 1 +} CLAMP_TYPE; + +typedef enum +{ + SIXTAP = 0, + BILINEAR = 1 +} INTERPOLATIONFILTERTYPE; + +typedef struct VP8_COMMON_RTCD +{ +#if CONFIG_RUNTIME_CPU_DETECT + vp8_idct_rtcd_vtable_t idct; + vp8_recon_rtcd_vtable_t recon; + vp8_subpix_rtcd_vtable_t subpix; + vp8_loopfilter_rtcd_vtable_t loopfilter; + vp8_postproc_rtcd_vtable_t postproc; +#else + int unused; +#endif +} VP8_COMMON_RTCD; + +typedef struct VP8Common +{ + struct vpx_internal_error_info error; + + DECLARE_ALIGNED(16, short, Y1dequant[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, Y2dequant[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, UVdequant[QINDEX_RANGE][4][4]); + + int Width; + int Height; + int horiz_scale; + int vert_scale; + + YUV_TYPE clr_type; + CLAMP_TYPE clamp_type; + + YV12_BUFFER_CONFIG last_frame; + YV12_BUFFER_CONFIG golden_frame; + YV12_BUFFER_CONFIG alt_ref_frame; + YV12_BUFFER_CONFIG new_frame; + YV12_BUFFER_CONFIG *frame_to_show; + YV12_BUFFER_CONFIG post_proc_buffer; + YV12_BUFFER_CONFIG temp_scale_frame; + + FRAME_TYPE last_frame_type; //Add to check if vp8_frame_init_loop_filter() can be skiped. + FRAME_TYPE frame_type; + + int show_frame; + + int frame_flags; + int MBs; + int mb_rows; + int mb_cols; + int mode_info_stride; + + // prfile settings + int mb_no_coeff_skip; + int no_lpf; + int simpler_lpf; + int use_bilinear_mc_filter; + int full_pixel; + + int base_qindex; + int last_kf_gf_q; // Q used on the last GF or KF + + int y1dc_delta_q; + int y2dc_delta_q; + int y2ac_delta_q; + int uvdc_delta_q; + int uvac_delta_q; + + unsigned int frames_since_golden; + unsigned int frames_till_alt_ref_frame; + unsigned char *gf_active_flags; // Record of which MBs still refer to last golden frame either directly or through 0,0 + int gf_active_count; + + /* We allocate a MODE_INFO struct for each macroblock, together with + an extra row on top and column on the left to simplify prediction. */ + + MODE_INFO *mip; /* Base of allocated array */ + MODE_INFO *mi; /* Corresponds to upper left visible macroblock */ + + + INTERPOLATIONFILTERTYPE mcomp_filter_type; + LOOPFILTERTYPE last_filter_type; + LOOPFILTERTYPE filter_type; + loop_filter_info lf_info[MAX_LOOP_FILTER+1]; + prototype_loopfilter_block((*lf_mbv)); + prototype_loopfilter_block((*lf_mbh)); + prototype_loopfilter_block((*lf_bv)); + prototype_loopfilter_block((*lf_bh)); + int filter_level; + int last_sharpness_level; + int sharpness_level; + + int refresh_last_frame; // Two state 0 = NO, 1 = YES + int refresh_golden_frame; // Two state 0 = NO, 1 = YES + int refresh_alt_ref_frame; // Two state 0 = NO, 1 = YES + + int copy_buffer_to_gf; // 0 none, 1 Last to GF, 2 ARF to GF + int copy_buffer_to_arf; // 0 none, 1 Last to ARF, 2 GF to ARF + + int refresh_entropy_probs; // Two state 0 = NO, 1 = YES + + int ref_frame_sign_bias[MAX_REF_FRAMES]; // Two state 0, 1 + + // Y,U,V,Y2 + ENTROPY_CONTEXT *above_context[4]; // row of context for each plane + ENTROPY_CONTEXT left_context[4][4]; // (up to) 4 contexts "" + + + // keyframe block modes are predicted by their above, left neighbors + + vp8_prob kf_bmode_prob [VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES-1]; + vp8_prob kf_ymode_prob [VP8_YMODES-1]; /* keyframe "" */ + vp8_prob kf_uv_mode_prob [VP8_UV_MODES-1]; + + + FRAME_CONTEXT lfc; // last frame entropy + FRAME_CONTEXT fc; // this frame entropy + + unsigned int current_video_frame; + + int near_boffset[3]; + int version; + + TOKEN_PARTITION multi_token_partition; + +#ifdef PACKET_TESTING + VP8_HEADER oh; +#endif + double bitrate; + double framerate; + +#if CONFIG_RUNTIME_CPU_DETECT + VP8_COMMON_RTCD rtcd; +#endif + struct postproc_state postproc_state; +} VP8_COMMON; + + +void vp8_adjust_mb_lf_value(MACROBLOCKD *mbd, int *filter_level); +void vp8_init_loop_filter(VP8_COMMON *cm); +extern void vp8_loop_filter_frame(VP8_COMMON *cm, MACROBLOCKD *mbd, int filt_val); + +#endif
diff --git a/vp8/common/onyxd.h b/vp8/common/onyxd.h new file mode 100644 index 0000000..644c0ec --- /dev/null +++ b/vp8/common/onyxd.h
@@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_VP8D_H +#define __INC_VP8D_H + + +/* Create/destroy static data structures. */ +#ifdef __cplusplus +extern "C" +{ +#endif +#include "type_aliases.h" +#include "vpx_scale/yv12config.h" +#include "ppflags.h" +#include "vpx_ports/mem.h" + + typedef void *VP8D_PTR; + typedef struct + { + int Width; + int Height; + int Version; + int postprocess; + int max_threads; + } VP8D_CONFIG; + typedef enum + { + VP8_LAST_FLAG = 1, + VP8_GOLD_FLAG = 2, + VP8_ALT_FLAG = 4 + } VP8_REFFRAME; + + typedef enum + { + VP8D_OK = 0 + } VP8D_SETTING; + + void vp8dx_initialize(void); + + void vp8dx_set_setting(VP8D_PTR comp, VP8D_SETTING oxst, int x); + + int vp8dx_get_setting(VP8D_PTR comp, VP8D_SETTING oxst); + + int vp8dx_receive_compressed_data(VP8D_PTR comp, unsigned long size, const unsigned char *dest, INT64 time_stamp); + int vp8dx_get_raw_frame(VP8D_PTR comp, YV12_BUFFER_CONFIG *sd, INT64 *time_stamp, INT64 *time_end_stamp, int deblock_level, int noise_level, int flags); + + int vp8dx_get_reference(VP8D_PTR comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + int vp8dx_set_reference(VP8D_PTR comp, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd); + + VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf); + + void vp8dx_remove_decompressor(VP8D_PTR comp); + +#ifdef __cplusplus +} +#endif + + +#endif
diff --git a/vp8/common/partialgfupdate.h b/vp8/common/partialgfupdate.h new file mode 100644 index 0000000..32a55ee --- /dev/null +++ b/vp8/common/partialgfupdate.h
@@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_PARTIALGFUPDATE_H +#define __INC_PARTIALGFUPDATE_H + +#include "onyxc_int.h" + +extern void update_gf_selective(ONYX_COMMON *cm, MACROBLOCKD *x); + +#endif
diff --git a/vp8/common/postproc.c b/vp8/common/postproc.c new file mode 100644 index 0000000..f019925 --- /dev/null +++ b/vp8/common/postproc.c
@@ -0,0 +1,641 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "vpx_scale/yv12config.h" +#include "postproc.h" +#include "vpx_scale/yv12extend.h" +#include "vpx_scale/vpxscale.h" +#include "systemdependent.h" + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +// global constants + +static const short kernel5[] = +{ + 1, 1, 4, 1, 1 +}; + +const short vp8_rv[] = +{ + 8, 5, 2, 2, 8, 12, 4, 9, 8, 3, + 0, 3, 9, 0, 0, 0, 8, 3, 14, 4, + 10, 1, 11, 14, 1, 14, 9, 6, 12, 11, + 8, 6, 10, 0, 0, 8, 9, 0, 3, 14, + 8, 11, 13, 4, 2, 9, 0, 3, 9, 6, + 1, 2, 3, 14, 13, 1, 8, 2, 9, 7, + 3, 3, 1, 13, 13, 6, 6, 5, 2, 7, + 11, 9, 11, 8, 7, 3, 2, 0, 13, 13, + 14, 4, 12, 5, 12, 10, 8, 10, 13, 10, + 4, 14, 4, 10, 0, 8, 11, 1, 13, 7, + 7, 14, 6, 14, 13, 2, 13, 5, 4, 4, + 0, 10, 0, 5, 13, 2, 12, 7, 11, 13, + 8, 0, 4, 10, 7, 2, 7, 2, 2, 5, + 3, 4, 7, 3, 3, 14, 14, 5, 9, 13, + 3, 14, 3, 6, 3, 0, 11, 8, 13, 1, + 13, 1, 12, 0, 10, 9, 7, 6, 2, 8, + 5, 2, 13, 7, 1, 13, 14, 7, 6, 7, + 9, 6, 10, 11, 7, 8, 7, 5, 14, 8, + 4, 4, 0, 8, 7, 10, 0, 8, 14, 11, + 3, 12, 5, 7, 14, 3, 14, 5, 2, 6, + 11, 12, 12, 8, 0, 11, 13, 1, 2, 0, + 5, 10, 14, 7, 8, 0, 4, 11, 0, 8, + 0, 3, 10, 5, 8, 0, 11, 6, 7, 8, + 10, 7, 13, 9, 2, 5, 1, 5, 10, 2, + 4, 3, 5, 6, 10, 8, 9, 4, 11, 14, + 0, 10, 0, 5, 13, 2, 12, 7, 11, 13, + 8, 0, 4, 10, 7, 2, 7, 2, 2, 5, + 3, 4, 7, 3, 3, 14, 14, 5, 9, 13, + 3, 14, 3, 6, 3, 0, 11, 8, 13, 1, + 13, 1, 12, 0, 10, 9, 7, 6, 2, 8, + 5, 2, 13, 7, 1, 13, 14, 7, 6, 7, + 9, 6, 10, 11, 7, 8, 7, 5, 14, 8, + 4, 4, 0, 8, 7, 10, 0, 8, 14, 11, + 3, 12, 5, 7, 14, 3, 14, 5, 2, 6, + 11, 12, 12, 8, 0, 11, 13, 1, 2, 0, + 5, 10, 14, 7, 8, 0, 4, 11, 0, 8, + 0, 3, 10, 5, 8, 0, 11, 6, 7, 8, + 10, 7, 13, 9, 2, 5, 1, 5, 10, 2, + 4, 3, 5, 6, 10, 8, 9, 4, 11, 14, + 3, 8, 3, 7, 8, 5, 11, 4, 12, 3, + 11, 9, 14, 8, 14, 13, 4, 3, 1, 2, + 14, 6, 5, 4, 4, 11, 4, 6, 2, 1, + 5, 8, 8, 12, 13, 5, 14, 10, 12, 13, + 0, 9, 5, 5, 11, 10, 13, 9, 10, 13, +}; + + +extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch); + +/*********************************************************************************************************** + */ +void vp8_post_proc_down_and_across_c +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +) +{ + unsigned char *p_src, *p_dst; + int row; + int col; + int i; + int v; + int pitch = src_pixels_per_line; + unsigned char d[8]; + (void)dst_pixels_per_line; + + for (row = 0; row < rows; row++) + { + // post_proc_down for one row + p_src = src_ptr; + p_dst = dst_ptr; + + for (col = 0; col < cols; col++) + { + + int kernel = 4; + int v = p_src[col]; + + for (i = -2; i <= 2; i++) + { + if (abs(v - p_src[col+i*pitch]) > flimit) + goto down_skip_convolve; + + kernel += kernel5[2+i] * p_src[col+i*pitch]; + } + + v = (kernel >> 3); + down_skip_convolve: + p_dst[col] = v; + } + + // now post_proc_across + p_src = dst_ptr; + p_dst = dst_ptr; + + for (i = 0; i < 8; i++) + d[i] = p_src[i]; + + for (col = 0; col < cols; col++) + { + int kernel = 4; + v = p_src[col]; + + d[col&7] = v; + + for (i = -2; i <= 2; i++) + { + if (abs(v - p_src[col+i]) > flimit) + goto across_skip_convolve; + + kernel += kernel5[2+i] * p_src[col+i]; + } + + d[col&7] = (kernel >> 3); + across_skip_convolve: + + if (col >= 2) + p_dst[col-2] = d[(col-2)&7]; + } + + //handle the last two pixels + p_dst[col-2] = d[(col-2)&7]; + p_dst[col-1] = d[(col-1)&7]; + + + //next row + src_ptr += pitch; + dst_ptr += pitch; + } +} + +int vp8_q2mbl(int x) +{ + if (x < 20) x = 20; + + x = 50 + (x - 50) * 10 / 8; + return x * x / 3; +} +void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit) +{ + int r, c, i; + + unsigned char *s = src; + unsigned char d[16]; + + + for (r = 0; r < rows; r++) + { + int sumsq = 0; + int sum = 0; + + for (i = -8; i <= 6; i++) + { + sumsq += s[i] * s[i]; + sum += s[i]; + d[i+8] = 0; + } + + for (c = 0; c < cols + 8; c++) + { + int x = s[c+7] - s[c-8]; + int y = s[c+7] + s[c-8]; + + sum += x; + sumsq += x * y; + + d[c&15] = s[c]; + + if (sumsq * 15 - sum * sum < flimit) + { + d[c&15] = (8 + sum + s[c]) >> 4; + } + + s[c-8] = d[(c-8)&15]; + } + + s += pitch; + } +} + + + + + +void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit) +{ + int r, c, i; + const short *rv3 = &vp8_rv[63&rand()]; + + for (c = 0; c < cols; c++) + { + unsigned char *s = &dst[c]; + int sumsq = 0; + int sum = 0; + unsigned char d[16]; + const short *rv2 = rv3 + ((c * 17) & 127); + + for (i = -8; i <= 6; i++) + { + sumsq += s[i*pitch] * s[i*pitch]; + sum += s[i*pitch]; + } + + for (r = 0; r < rows + 8; r++) + { + sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch]; + sum += s[7*pitch] - s[-8*pitch]; + d[r&15] = s[0]; + + if (sumsq * 15 - sum * sum < flimit) + { + d[r&15] = (rv2[r&127] + sum + s[0]) >> 4; + } + + s[-8*pitch] = d[(r-8)&15]; + s += pitch; + } + } +} + + +static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag, + vp8_postproc_rtcd_vtable_t *rtcd) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) low_var_thresh; + (void) flag; + + POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl); + POSTPROC_INVOKE(rtcd, across)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q)); + POSTPROC_INVOKE(rtcd, down)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q)); + + POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + +} + +extern void vp8_deblock(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag, + vp8_postproc_rtcd_vtable_t *rtcd) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) low_var_thresh; + (void) flag; + + POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl); + POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); + POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); +} + +void vp8_de_noise(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag, + vp8_postproc_rtcd_vtable_t *rtcd) +{ + double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065; + int ppl = (int)(level + .5); + (void) post; + (void) low_var_thresh; + (void) flag; + + POSTPROC_INVOKE(rtcd, downacross)( + source->y_buffer + 2 * source->y_stride + 2, + source->y_buffer + 2 * source->y_stride + 2, + source->y_stride, + source->y_stride, + source->y_height - 4, + source->y_width - 4, + ppl); + POSTPROC_INVOKE(rtcd, downacross)( + source->u_buffer + 2 * source->uv_stride + 2, + source->u_buffer + 2 * source->uv_stride + 2, + source->uv_stride, + source->uv_stride, + source->uv_height - 4, + source->uv_width - 4, ppl); + POSTPROC_INVOKE(rtcd, downacross)( + source->v_buffer + 2 * source->uv_stride + 2, + source->v_buffer + 2 * source->uv_stride + 2, + source->uv_stride, + source->uv_stride, + source->uv_height - 4, + source->uv_width - 4, ppl); + +} + + +//Notes: It is better to change CHAR to unsigned or signed to +//avoid error on ARM platform. +char vp8_an[8][64][3072]; +int vp8_cd[8][64]; + + +double vp8_gaussian(double sigma, double mu, double x) +{ + return 1 / (sigma * sqrt(2.0 * 3.14159265)) * + (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma))); +} + +extern void (*vp8_clear_system_state)(void); + + +static void fillrd(struct postproc_state *state, int q, int a) +{ + char char_dist[300]; + + double sigma; + int ai = a, qi = q, i; + + vp8_clear_system_state(); + + + sigma = ai + .5 + .6 * (63 - qi) / 63.0; + + // set up a lookup table of 256 entries that matches + // a gaussian distribution with sigma determined by q. + // + { + double i; + int next, j; + + next = 0; + + for (i = -32; i < 32; i++) + { + int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i)); + + if (a) + { + for (j = 0; j < a; j++) + { + char_dist[next+j] = (char) i; + } + + next = next + j; + } + + } + + for (next = next; next < 256; next++) + char_dist[next] = 0; + + } + + for (i = 0; i < 3072; i++) + { + state->noise[i] = char_dist[rand() & 0xff]; + } + + for (i = 0; i < 16; i++) + { + state->blackclamp[i] = -char_dist[0]; + state->whiteclamp[i] = -char_dist[0]; + state->bothclamp[i] = -2 * char_dist[0]; + } + + state->last_q = q; + state->last_noise = a; +} + +/**************************************************************************** + * + * ROUTINE : plane_add_noise_c + * + * INPUTS : unsigned char *Start starting address of buffer to add gaussian + * noise to + * unsigned int Width width of plane + * unsigned int Height height of plane + * int Pitch distance between subsequent lines of frame + * int q quantizer used to determine amount of noise + * to add + * + * OUTPUTS : None. + * + * RETURNS : void. + * + * FUNCTION : adds gaussian noise to a plane of pixels + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_plane_add_noise_c(unsigned char *Start, char *noise, + char blackclamp[16], + char whiteclamp[16], + char bothclamp[16], + unsigned int Width, unsigned int Height, int Pitch) +{ + unsigned int i, j; + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = (char *)(noise + (rand() & 0xff)); + + for (j = 0; j < Width; j++) + { + if (Pos[j] < blackclamp[0]) + Pos[j] = blackclamp[0]; + + if (Pos[j] > 255 + whiteclamp[0]) + Pos[j] = 255 + whiteclamp[0]; + + Pos[j] += Ref[j]; + } + } +} + +#if CONFIG_RUNTIME_CPU_DETECT +#define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc) +#else +#define RTCD_VTABLE(oci) NULL +#endif + +int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags) +{ + char message[512]; + int q = oci->filter_level * 10 / 6; + + if (!oci->frame_to_show) + return -1; + + if (q > 63) + q = 63; + + if (!flags) + { + *dest = *oci->frame_to_show; + + // handle problem with extending borders + dest->y_width = oci->Width; + dest->y_height = oci->Height; + dest->uv_height = dest->y_height / 2; + return 0; + + } + +#if ARCH_X86||ARCH_X86_64 + vpx_reset_mmx_state(); +#endif + + if (flags & VP8D_DEMACROBLOCK) + { + vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer, + q + (deblock_level - 5) * 10, 1, 0, RTCD_VTABLE(oci)); + } + else if (flags & VP8D_DEBLOCK) + { + vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer, + q, 1, 0, RTCD_VTABLE(oci)); + } + else + { + vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer); + } + + if (flags & VP8D_ADDNOISE) + { + if (oci->postproc_state.last_q != q + || oci->postproc_state.last_noise != noise_level) + { + fillrd(&oci->postproc_state, 63 - q, noise_level); + } + + POSTPROC_INVOKE(RTCD_VTABLE(oci), addnoise) + (oci->post_proc_buffer.y_buffer, + oci->postproc_state.noise, + oci->postproc_state.blackclamp, + oci->postproc_state.whiteclamp, + oci->postproc_state.bothclamp, + oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height, + oci->post_proc_buffer.y_stride); + } + + if (flags & VP8D_DEBUG_LEVEL1) + { + sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d", + (oci->frame_type == KEY_FRAME), + oci->refresh_golden_frame, + oci->base_qindex, + oci->filter_level, + flags, + oci->mb_cols, oci->mb_rows); + vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride); + } + else if (flags & VP8D_DEBUG_LEVEL2) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = oci->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + // vp8_filter each macro block + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a'); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; //border + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + else if (flags & VP8D_DEBUG_LEVEL3) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = oci->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + // vp8_filter each macro block + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + if (oci->frame_type == KEY_FRAME) + sprintf(zz, "a"); + else + sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0'); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; //border + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + else if (flags & VP8D_DEBUG_LEVEL4) + { + sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate); + vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride); +#if 0 + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = oci->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + // vp8_filter each macro block + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0'); + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; //border + y_ptr += post->y_stride * 16 - post->y_width; + + } + +#endif + + } + + + + *dest = oci->post_proc_buffer; + + // handle problem with extending borders + dest->y_width = oci->Width; + dest->y_height = oci->Height; + dest->uv_height = dest->y_height / 2; + return 0; +}
diff --git a/vp8/common/postproc.h b/vp8/common/postproc.h new file mode 100644 index 0000000..c45fe92 --- /dev/null +++ b/vp8/common/postproc.h
@@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef POSTPROC_H +#define POSTPROC_H + +#define prototype_postproc_inplace(sym)\ + void sym (unsigned char *dst, int pitch, int rows, int cols,int flimit) + +#define prototype_postproc(sym)\ + void sym (unsigned char *src, unsigned char *dst, int src_pitch,\ + int dst_pitch, int rows, int cols, int flimit) + +#define prototype_postproc_addnoise(sym) \ + void sym (unsigned char *s, char *noise, char blackclamp[16],\ + char whiteclamp[16], char bothclamp[16],\ + unsigned int w, unsigned int h, int pitch) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/postproc_x86.h" +#endif + +#ifndef vp8_postproc_down +#define vp8_postproc_down vp8_mbpost_proc_down_c +#endif +extern prototype_postproc_inplace(vp8_postproc_down); + +#ifndef vp8_postproc_across +#define vp8_postproc_across vp8_mbpost_proc_across_ip_c +#endif +extern prototype_postproc_inplace(vp8_postproc_across); + +#ifndef vp8_postproc_downacross +#define vp8_postproc_downacross vp8_post_proc_down_and_across_c +#endif +extern prototype_postproc(vp8_postproc_downacross); + +#ifndef vp8_postproc_addnoise +#define vp8_postproc_addnoise vp8_plane_add_noise_c +#endif +extern prototype_postproc_addnoise(vp8_postproc_addnoise); + + +typedef prototype_postproc((*vp8_postproc_fn_t)); +typedef prototype_postproc_inplace((*vp8_postproc_inplace_fn_t)); +typedef prototype_postproc_addnoise((*vp8_postproc_addnoise_fn_t)); +typedef struct +{ + vp8_postproc_inplace_fn_t down; + vp8_postproc_inplace_fn_t across; + vp8_postproc_fn_t downacross; + vp8_postproc_addnoise_fn_t addnoise; +} vp8_postproc_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define POSTPROC_INVOKE(ctx,fn) (ctx)->fn +#else +#define POSTPROC_INVOKE(ctx,fn) vp8_postproc_##fn +#endif + +#include "vpx_ports/mem.h" +struct postproc_state +{ + int last_q; + int last_noise; + char noise[3072]; + DECLARE_ALIGNED(16, char, blackclamp[16]); + DECLARE_ALIGNED(16, char, whiteclamp[16]); + DECLARE_ALIGNED(16, char, bothclamp[16]); +}; +#include "onyxc_int.h" +#include "ppflags.h" +int vp8_post_proc_frame(struct VP8Common *oci, YV12_BUFFER_CONFIG *dest, + int deblock_level, int noise_level, int flags); + + +void vp8_de_noise(YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *post, + int q, + int low_var_thresh, + int flag, + vp8_postproc_rtcd_vtable_t *rtcd); +#endif
diff --git a/vp8/common/ppc/copy_altivec.asm b/vp8/common/ppc/copy_altivec.asm new file mode 100644 index 0000000..e87eb21 --- /dev/null +++ b/vp8/common/ppc/copy_altivec.asm
@@ -0,0 +1,46 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl copy_mem16x16_ppc + +;# r3 unsigned char *src +;# r4 int src_stride +;# r5 unsigned char *dst +;# r6 int dst_stride + +;# Make the assumption that input will not be aligned, +;# but the output will be. So two reads and a perm +;# for the input, but only one store for the output. +copy_mem16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xe000 + mtspr 256, r12 ;# set VRSAVE + + li r10, 16 + mtctr r10 + +cp_16x16_loop: + lvsl v0, 0, r3 ;# permutate value for alignment + + lvx v1, 0, r3 + lvx v2, r10, r3 + + vperm v1, v1, v2, v0 + + stvx v1, 0, r5 + + add r3, r3, r4 ;# increment source pointer + add r5, r5, r6 ;# increment destination pointer + + bdnz cp_16x16_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr
diff --git a/vp8/common/ppc/filter_altivec.asm b/vp8/common/ppc/filter_altivec.asm new file mode 100644 index 0000000..2a35507 --- /dev/null +++ b/vp8/common/ppc/filter_altivec.asm
@@ -0,0 +1,1012 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl sixtap_predict_ppc + .globl sixtap_predict8x4_ppc + .globl sixtap_predict8x8_ppc + .globl sixtap_predict16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_hfilter V0, V1 + load_c \V0, HFilter, r5, r9, r10 + + addi r5, r5, 16 + lvx \V1, r5, r10 +.endm + +;# Vertical filtering +.macro Vprolog + load_c v0, VFilter, r6, r3, r10 + + vspltish v5, 8 + vspltish v6, 3 + vslh v6, v5, v6 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v1, v0, 1 + vspltb v2, v0, 2 + vspltb v3, v0, 3 + vspltb v4, v0, 4 + vspltb v5, v0, 5 + vspltb v0, v0, 0 +.endm + +.macro vpre_load + Vprolog + li r10, 16 + lvx v10, 0, r9 ;# v10..v14 = first 5 rows + lvx v11, r10, r9 + addi r9, r9, 32 + lvx v12, 0, r9 + lvx v13, r10, r9 + addi r9, r9, 32 + lvx v14, 0, r9 +.endm + +.macro Msum Re, Ro, V, T, TMP + ;# (Re,Ro) += (V*T) + vmuleub \TMP, \V, \T ;# trashes v8 + vadduhm \Re, \Re, \TMP ;# Re = evens, saturation unnecessary + vmuloub \TMP, \V, \T + vadduhm \Ro, \Ro, \TMP ;# Ro = odds +.endm + +.macro vinterp_no_store P0 P1 P2 P3 P4 P5 + vmuleub v8, \P0, v0 ;# 64 + 4 positive taps + vadduhm v16, v6, v8 + vmuloub v8, \P0, v0 + vadduhm v17, v6, v8 + Msum v16, v17, \P2, v2, v8 + Msum v16, v17, \P3, v3, v8 + Msum v16, v17, \P5, v5, v8 + + vmuleub v18, \P1, v1 ;# 2 negative taps + vmuloub v19, \P1, v1 + Msum v18, v19, \P4, v4, v8 + + vsubuhs v16, v16, v18 ;# subtract neg from pos + vsubuhs v17, v17, v19 + vsrh v16, v16, v7 ;# divide by 128 + vsrh v17, v17, v7 ;# v16 v17 = evens, odds + vmrghh v18, v16, v17 ;# v18 v19 = 16-bit result in order + vmrglh v19, v16, v17 + vpkuhus \P0, v18, v19 ;# P0 = 8-bit result +.endm + +.macro vinterp_no_store_8x8 P0 P1 P2 P3 P4 P5 + vmuleub v24, \P0, v13 ;# 64 + 4 positive taps + vadduhm v21, v20, v24 + vmuloub v24, \P0, v13 + vadduhm v22, v20, v24 + Msum v21, v22, \P2, v15, v25 + Msum v21, v22, \P3, v16, v25 + Msum v21, v22, \P5, v18, v25 + + vmuleub v23, \P1, v14 ;# 2 negative taps + vmuloub v24, \P1, v14 + Msum v23, v24, \P4, v17, v25 + + vsubuhs v21, v21, v23 ;# subtract neg from pos + vsubuhs v22, v22, v24 + vsrh v21, v21, v19 ;# divide by 128 + vsrh v22, v22, v19 ;# v16 v17 = evens, odds + vmrghh v23, v21, v22 ;# v18 v19 = 16-bit result in order + vmrglh v24, v21, v22 + vpkuhus \P0, v23, v24 ;# P0 = 8-bit result +.endm + + +.macro Vinterp P0 P1 P2 P3 P4 P5 + vinterp_no_store \P0, \P1, \P2, \P3, \P4, \P5 + stvx \P0, 0, r7 + add r7, r7, r8 ;# 33 ops per 16 pels +.endm + + +.macro luma_v P0, P1, P2, P3, P4, P5 + addi r9, r9, 16 ;# P5 = newest input row + lvx \P5, 0, r9 + Vinterp \P0, \P1, \P2, \P3, \P4, \P5 +.endm + +.macro luma_vtwo + luma_v v10, v11, v12, v13, v14, v15 + luma_v v11, v12, v13, v14, v15, v10 +.endm + +.macro luma_vfour + luma_vtwo + luma_v v12, v13, v14, v15, v10, v11 + luma_v v13, v14, v15, v10, v11, v12 +.endm + +.macro luma_vsix + luma_vfour + luma_v v14, v15, v10, v11, v12, v13 + luma_v v15, v10, v11, v12, v13, v14 +.endm + +.macro Interp4 R I I4 + vmsummbm \R, v13, \I, v15 + vmsummbm \R, v14, \I4, \R +.endm + +.macro Read8x8 VD, RS, RP, increment_counter + lvsl v21, 0, \RS ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx \VD, 0, \RS + lvx v20, r10, \RS + +.if \increment_counter + add \RS, \RS, \RP +.endif + + vperm \VD, \VD, v20, v21 +.endm + +.macro interp_8x8 R + vperm v20, \R, \R, v16 ;# v20 = 0123 1234 2345 3456 + vperm v21, \R, \R, v17 ;# v21 = 4567 5678 6789 789A + Interp4 v20, v20, v21 ;# v20 = result 0 1 2 3 + vperm \R, \R, \R, v18 ;# R = 89AB 9ABC ABCx BCxx + Interp4 v21, v21, \R ;# v21 = result 4 5 6 7 + + vpkswus \R, v20, v21 ;# R = 0 1 2 3 4 5 6 7 + vsrh \R, \R, v19 + + vpkuhus \R, \R, \R ;# saturate and pack + +.endm + +.macro Read4x4 VD, RS, RP, increment_counter + lvsl v21, 0, \RS ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v20, 0, \RS + +.if \increment_counter + add \RS, \RS, \RP +.endif + + vperm \VD, v20, v20, v21 +.endm + .text + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +sixtap_predict_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xff87 + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- vertical_only_4x4 + + ;# load up horizontal filter + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_4x4 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + + b second_pass_4x4 + +vertical_only_4x4: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_4x4: + load_c v20, b_hilo_4x4, 0, r9, r10 + load_c v21, b_hilo, 0, r9, r10 + + ;# reposition input so that it can go through the + ;# filtering phase with one pass. + vperm v0, v0, v1, v20 ;# 0 1 x x + vperm v2, v2, v3, v20 ;# 2 3 x x + vperm v4, v4, v5, v20 ;# 4 5 x x + vperm v6, v6, v7, v20 ;# 6 7 x x + + vperm v0, v0, v2, v21 ;# 0 1 2 3 + vperm v4, v4, v6, v21 ;# 4 5 6 7 + + vsldoi v1, v0, v4, 4 + vsldoi v2, v0, v4, 8 + vsldoi v3, v0, v4, 12 + + vsldoi v5, v4, v8, 4 + + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + + stvx v0, 0, r1 + + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 4(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 8(r1) + stw r0, 0(r7) + add r7, r7, r8 + + lwz r0, 12(r1) + stw r0, 0(r7) + + b exit_4x4 + +store_4x4: + + stvx v2, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v3, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v4, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v5, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + +exit_4x4: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro w_8x8 V, D, R, P + stvx \V, 0, r1 + lwz \R, 0(r1) + stw \R, 0(r7) + lwz \R, 4(r1) + stw \R, 4(r7) + add \D, \D, \P +.endm + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +sixtap_predict8x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- second_pass_pre_copy_8x4 + + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_8x4 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + + b second_pass_8x4 + +second_pass_pre_copy_8x4: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_8x4: + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + vinterp_no_store_8x8 v1, v2, v3, v4, v5, v6 + vinterp_no_store_8x8 v2, v3, v4, v5, v6, v7 + vinterp_no_store_8x8 v3, v4, v5, v6, v7, v8 + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x4 + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + + b exit_8x4 + +store_aligned_8x4: + + load_c v10, b_hilo, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + + b exit_8x4 + +store_8x4: + cmpi cr0, r8, 8 + beq cr0, store_aligned2_8x4 + + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + + b exit_8x4 + +store_aligned2_8x4: + load_c v10, b_hilo, 0, r9, r10 + + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + +exit_8x4: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +;# Because the width that needs to be filtered will fit in a single altivec +;# register there is no need to loop. Everything can stay in registers. +sixtap_predict8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + slwi. r5, r5, 5 ;# index into horizontal filter array + + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq- second_pass_pre_copy_8x8 + + load_hfilter v13, v14 + + ;# rounding added in on the multiply + vspltisw v16, 8 + vspltisw v15, 3 + vslw v15, v16, v15 ;# 0x00000040000000400000004000000040 + + ;# Load up permutation constants + load_c v16, B_0123, 0, r9, r10 + load_c v17, B_4567, 0, r9, r10 + load_c v18, B_89AB, 0, r9, r10 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + addi r9, r3, 0 + li r10, 16 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + Read8x8 v9, r3, r4, 1 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# filter a line + interp_8x8 v2 + interp_8x8 v3 + interp_8x8 v4 + interp_8x8 v5 + interp_8x8 v6 + interp_8x8 v7 + interp_8x8 v8 + interp_8x8 v9 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional 5 lines that are needed + ;# for the vertical filter. + beq- store_8x8 + + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r9, r9, r4 + sub r9, r9, r4 + + Read8x8 v0, r9, r4, 1 + Read8x8 v1, r9, r4, 0 + Read8x8 v10, r3, r4, 1 + Read8x8 v11, r3, r4, 1 + Read8x8 v12, r3, r4, 0 + + interp_8x8 v0 + interp_8x8 v1 + interp_8x8 v10 + interp_8x8 v11 + interp_8x8 v12 + + b second_pass_8x8 + +second_pass_pre_copy_8x8: + ;# only needed if there is a vertical filter present + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + li r10, 16 + + Read8x8 v0, r3, r4, 1 + Read8x8 v1, r3, r4, 1 + Read8x8 v2, r3, r4, 1 + Read8x8 v3, r3, r4, 1 + Read8x8 v4, r3, r4, 1 + Read8x8 v5, r3, r4, 1 + Read8x8 v6, r3, r4, 1 + Read8x8 v7, r3, r4, 1 + Read8x8 v8, r3, r4, 1 + Read8x8 v9, r3, r4, 1 + Read8x8 v10, r3, r4, 1 + Read8x8 v11, r3, r4, 1 + Read8x8 v12, r3, r4, 0 + + slwi r6, r6, 4 ;# index into vertical filter array + +second_pass_8x8: + load_c v13, VFilter, r6, r9, r10 + + vspltish v15, 8 + vspltish v20, 3 + vslh v20, v15, v20 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + vspltb v14, v13, 1 + vspltb v15, v13, 2 + vspltb v16, v13, 3 + vspltb v17, v13, 4 + vspltb v18, v13, 5 + vspltb v13, v13, 0 + + vinterp_no_store_8x8 v0, v1, v2, v3, v4, v5 + vinterp_no_store_8x8 v1, v2, v3, v4, v5, v6 + vinterp_no_store_8x8 v2, v3, v4, v5, v6, v7 + vinterp_no_store_8x8 v3, v4, v5, v6, v7, v8 + vinterp_no_store_8x8 v4, v5, v6, v7, v8, v9 + vinterp_no_store_8x8 v5, v6, v7, v8, v9, v10 + vinterp_no_store_8x8 v6, v7, v8, v9, v10, v11 + vinterp_no_store_8x8 v7, v8, v9, v10, v11, v12 + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x8 + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + + b exit_8x8 + +store_aligned_8x8: + + load_c v10, b_hilo, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + + b exit_8x8 + +store_8x8: + cmpi cr0, r8, 8 + beq cr0, store_aligned2_8x8 + + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + w_8x8 v8, r7, r0, r8 + w_8x8 v9, r7, r0, r8 + + b exit_8x8 + +store_aligned2_8x8: + load_c v10, b_hilo, 0, r9, r10 + + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + vperm v8, v8, v9, v10 + + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + addi r7, r7, 16 + stvx v8, 0, r7 + +exit_8x8: + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch + +;# Two pass filtering. First pass is Horizontal edges, second pass is vertical +;# edges. One of the filters can be null, but both won't be. Needs to use a +;# temporary buffer because the source buffer can't be modified and the buffer +;# for the destination is not large enough to hold the temporary data. +sixtap_predict16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xf000 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-416(r1) ;# create space on the stack + + ;# Three possiblities + ;# 1. First filter is null. Don't use a temp buffer. + ;# 2. Second filter is null. Don't use a temp buffer. + ;# 3. Neither are null, use temp buffer. + + ;# First Pass (horizontal edge) + ;# setup pointers for src + ;# if possiblity (1) then setup the src pointer to be the orginal and jump + ;# to second pass. this is based on if x_offset is 0. + + ;# load up horizontal filter + slwi. r5, r5, 5 ;# index into horizontal filter array + + load_hfilter v4, v5 + + beq- copy_horizontal_16x21 + + ;# Back off input buffer by 2 bytes. Need 2 before and 3 after + addi r3, r3, -2 + + slwi. r6, r6, 4 ;# index into vertical filter array + + ;# setup constants + ;# v14 permutation value for alignment + load_c v14, b_hperm, 0, r9, r10 + + ;# These statements are guessing that there won't be a second pass, + ;# but if there is then inside the bypass they need to be set + li r0, 16 ;# prepare for no vertical filter + + ;# Change the output pointer and pitch to be the actual + ;# desination instead of a temporary buffer. + addi r9, r7, 0 + addi r5, r8, 0 + + ;# no vertical filter, so write the output from the first pass + ;# directly into the output buffer. + beq- no_vertical_filter_bypass + + ;# if the second filter is not null then need to back off by 2*pitch + sub r3, r3, r4 + sub r3, r3, r4 + + ;# setup counter for the number of lines that are going to be filtered + li r0, 21 + + ;# use the stack as temporary storage + la r9, 48(r1) + li r5, 16 + +no_vertical_filter_bypass: + + mtctr r0 + + ;# rounding added in on the multiply + vspltisw v10, 8 + vspltisw v12, 3 + vslw v12, v10, v12 ;# 0x00000040000000400000004000000040 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v13, 7 + + ;# index to the next set of vectors in the row. + li r10, 16 + li r12, 32 + +horizontal_loop_16x16: + + lvsl v15, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v1, 0, r3 + lvx v2, r10, r3 + lvx v3, r12, r3 + + vperm v8, v1, v2, v15 + vperm v9, v2, v3, v15 ;# v8 v9 = 21 input pixels left-justified + + vsldoi v11, v8, v9, 4 + + ;# set 0 + vmsummbm v6, v4, v8, v12 ;# taps times elements + vmsummbm v0, v5, v11, v6 + + ;# set 1 + vsldoi v10, v8, v9, 1 + vsldoi v11, v8, v9, 5 + + vmsummbm v6, v4, v10, v12 + vmsummbm v1, v5, v11, v6 + + ;# set 2 + vsldoi v10, v8, v9, 2 + vsldoi v11, v8, v9, 6 + + vmsummbm v6, v4, v10, v12 + vmsummbm v2, v5, v11, v6 + + ;# set 3 + vsldoi v10, v8, v9, 3 + vsldoi v11, v8, v9, 7 + + vmsummbm v6, v4, v10, v12 + vmsummbm v3, v5, v11, v6 + + vpkswus v0, v0, v1 ;# v0 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v1, v2, v3 ;# v1 = 2 6 A E 3 7 B F + + vsrh v0, v0, v13 ;# divide v0, v1 by 128 + vsrh v1, v1, v13 + + vpkuhus v0, v0, v1 ;# v0 = scrambled 8-bit result + vperm v0, v0, v0, v14 ;# v0 = correctly-ordered result + + stvx v0, 0, r9 + add r9, r9, r5 + + add r3, r3, r4 + + bdnz horizontal_loop_16x16 + + ;# check again to see if vertical filter needs to be done. + cmpi cr0, r6, 0 + beq cr0, end_16x16 + + ;# yes there is, so go to the second pass + b second_pass_16x16 + +copy_horizontal_16x21: + li r10, 21 + mtctr r10 + + li r10, 16 + + sub r3, r3, r4 + sub r3, r3, r4 + + ;# this is done above if there is a horizontal filter, + ;# if not it needs to be done down here. + slwi r6, r6, 4 ;# index into vertical filter array + + ;# always write to the stack when doing a horizontal copy + la r9, 48(r1) + +copy_horizontal_loop_16x21: + lvsl v15, 0, r3 ;# permutate value for alignment + + lvx v1, 0, r3 + lvx v2, r10, r3 + + vperm v8, v1, v2, v15 + + stvx v8, 0, r9 + addi r9, r9, 16 + + add r3, r3, r4 + + bdnz copy_horizontal_loop_16x21 + +second_pass_16x16: + + ;# always read from the stack when doing a vertical filter + la r9, 48(r1) + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v7, 7 + + vpre_load + + luma_vsix + luma_vsix + luma_vfour + +end_16x16: + + addi r1, r1, 416 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +HFilter: + .byte 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, -6,123, 12, 0, -6,123, 12, 0, -6,123, 12, 0, -6,123, 12 + .byte -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0 + .byte 2,-11,108, 36, 2,-11,108, 36, 2,-11,108, 36, 2,-11,108, 36 + .byte -8, 1, 0, 0, -8, 1, 0, 0, -8, 1, 0, 0, -8, 1, 0, 0 + .byte 0, -9, 93, 50, 0, -9, 93, 50, 0, -9, 93, 50, 0, -9, 93, 50 + .byte -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0 + .byte 3,-16, 77, 77, 3,-16, 77, 77, 3,-16, 77, 77, 3,-16, 77, 77 + .byte -16, 3, 0, 0,-16, 3, 0, 0,-16, 3, 0, 0,-16, 3, 0, 0 + .byte 0, -6, 50, 93, 0, -6, 50, 93, 0, -6, 50, 93, 0, -6, 50, 93 + .byte -9, 0, 0, 0, -9, 0, 0, 0, -9, 0, 0, 0, -9, 0, 0, 0 + .byte 1, -8, 36,108, 1, -8, 36,108, 1, -8, 36,108, 1, -8, 36,108 + .byte -11, 2, 0, 0,-11, 2, 0, 0,-11, 2, 0, 0,-11, 2, 0, 0 + .byte 0, -1, 12,123, 0, -1, 12,123, 0, -1, 12,123, 0, -1, 12,123 + .byte -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0, -6, 0, 0, 0 + + .align 4 +VFilter: + .byte 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 6,123, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 2, 11,108, 36, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 9, 93, 50, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 3, 16, 77, 77, 16, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 6, 50, 93, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 1, 8, 36,108, 11, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 1, 12,123, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + .align 4 +b_hperm: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +B_0123: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +B_4567: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + + .align 4 +B_89AB: + .byte 8, 9, 10, 11, 9, 10, 11, 12, 10, 11, 12, 13, 11, 12, 13, 14 + + .align 4 +b_hilo: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 + + .align 4 +b_hilo_4x4: + .byte 0, 1, 2, 3, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/vp8/common/ppc/filter_bilinear_altivec.asm b/vp8/common/ppc/filter_bilinear_altivec.asm new file mode 100644 index 0000000..27e02a8 --- /dev/null +++ b/vp8/common/ppc/filter_bilinear_altivec.asm
@@ -0,0 +1,676 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl bilinear_predict4x4_ppc + .globl bilinear_predict8x4_ppc + .globl bilinear_predict8x8_ppc + .globl bilinear_predict16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_vfilter V0, V1 + load_c \V0, vfilter_b, r6, r9, r10 + + addi r6, r6, 16 + lvx \V1, r6, r10 +.endm + +.macro HProlog jump_label + ;# load up horizontal filter + slwi. r5, r5, 4 ;# index into horizontal filter array + + ;# index to the next set of vectors in the row. + li r10, 16 + li r12, 32 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq \jump_label + + load_c v20, hfilter_b, r5, r9, r0 + + ;# setup constants + ;# v14 permutation value for alignment + load_c v28, b_hperm_b, 0, r9, r0 + + ;# rounding added in on the multiply + vspltisw v21, 8 + vspltisw v18, 3 + vslw v18, v21, v18 ;# 0x00000040000000400000004000000040 + + slwi. r6, r6, 5 ;# index into vertical filter array +.endm + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro HFilter V + vperm v24, v21, v21, v10 ;# v20 = 0123 1234 2345 3456 + vperm v25, v21, v21, v11 ;# v21 = 4567 5678 6789 789A + + vmsummbm v24, v20, v24, v18 + vmsummbm v25, v20, v25, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + + vpkuhus \V, v24, v24 ;# \V = scrambled 8-bit result +.endm + +.macro hfilter_8 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 9 bytes wide, output is 8 bytes. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + + HFilter \V +.endm + + +.macro load_and_align_8 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + + vperm \V, v21, v22, v17 +.endm + +.macro write_aligned_8 V, increment_counter + stvx \V, 0, r7 + +.if \increment_counter + add r7, r7, r8 +.endif +.endm + +.macro vfilter_16 P0 P1 + vmuleub v22, \P0, v20 ;# 64 + 4 positive taps + vadduhm v22, v18, v22 + vmuloub v23, \P0, v20 + vadduhm v23, v18, v23 + + vmuleub v24, \P1, v21 + vadduhm v22, v22, v24 ;# Re = evens, saturation unnecessary + vmuloub v25, \P1, v21 + vadduhm v23, v23, v25 ;# Ro = odds + + vsrh v22, v22, v19 ;# divide by 128 + vsrh v23, v23, v19 ;# v16 v17 = evens, odds + vmrghh \P0, v22, v23 ;# v18 v19 = 16-bit result in order + vmrglh v23, v22, v23 + vpkuhus \P0, \P0, v23 ;# P0 = 8-bit result +.endm + + +.macro w_8x8 V, D, R, P + stvx \V, 0, r1 + lwz \R, 0(r1) + stw \R, 0(r7) + lwz \R, 4(r1) + stw \R, 4(r7) + add \D, \D, \P +.endm + + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict4x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_4x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_4x4_b + + hfilter_8 v4, 0 + + b second_pass_4x4_b + +second_pass_4x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + +second_pass_4x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +store_out_4x4_b: + + stvx v0, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v1, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v2, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + add r7, r7, r8 + + stvx v3, 0, r1 + lwz r0, 0(r1) + stw r0, 0(r7) + +exit_4x4: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict8x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_8x4_b + + hfilter_8 v4, 0 + + b second_pass_8x4_b + +second_pass_8x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + +second_pass_8x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +store_out_8x4_b: + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x4_b + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + + b exit_8x4 + +store_aligned_8x4_b: + load_c v10, b_hilo_b, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + +exit_8x4: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff0 + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x8_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r9, r12 + load_c v11, b_4567_b, 0, r9, r12 + + hfilter_8 v0, 1 + hfilter_8 v1, 1 + hfilter_8 v2, 1 + hfilter_8 v3, 1 + hfilter_8 v4, 1 + hfilter_8 v5, 1 + hfilter_8 v6, 1 + hfilter_8 v7, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_8x8_b + + hfilter_8 v8, 0 + + b second_pass_8x8_b + +second_pass_8x8_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_8 v0, 1 + load_and_align_8 v1, 1 + load_and_align_8 v2, 1 + load_and_align_8 v3, 1 + load_and_align_8 v4, 1 + load_and_align_8 v5, 1 + load_and_align_8 v6, 1 + load_and_align_8 v7, 1 + load_and_align_8 v8, 0 + +second_pass_8x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +store_out_8x8_b: + + cmpi cr0, r8, 8 + beq cr0, store_aligned_8x8_b + + w_8x8 v0, r7, r0, r8 + w_8x8 v1, r7, r0, r8 + w_8x8 v2, r7, r0, r8 + w_8x8 v3, r7, r0, r8 + w_8x8 v4, r7, r0, r8 + w_8x8 v5, r7, r0, r8 + w_8x8 v6, r7, r0, r8 + w_8x8 v7, r7, r0, r8 + + b exit_8x8 + +store_aligned_8x8_b: + load_c v10, b_hilo_b, 0, r9, r10 + + vperm v0, v0, v1, v10 + vperm v2, v2, v3, v10 + vperm v4, v4, v5, v10 + vperm v6, v6, v7, v10 + + stvx v0, 0, r7 + addi r7, r7, 16 + stvx v2, 0, r7 + addi r7, r7, 16 + stvx v4, 0, r7 + addi r7, r7, 16 + stvx v6, 0, r7 + +exit_8x8: + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro hfilter_16 V, increment_counter + + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + lvx v23, r12, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + vperm v22, v22, v23, v17 ;# v8 v9 = 21 input pixels left-justified + + ;# set 0 + vmsummbm v24, v20, v21, v18 ;# taps times elements + + ;# set 1 + vsldoi v23, v21, v22, 1 + vmsummbm v25, v20, v23, v18 + + ;# set 2 + vsldoi v23, v21, v22, 2 + vmsummbm v26, v20, v23, v18 + + ;# set 3 + vsldoi v23, v21, v22, 3 + vmsummbm v27, v20, v23, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v25, v26, v27 ;# v25 = 2 6 A E 3 7 B F + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + vsrh v25, v25, v19 + + vpkuhus \V, v24, v25 ;# \V = scrambled 8-bit result + vperm \V, \V, v0, v28 ;# \V = correctly-ordered result +.endm + +.macro load_and_align_16 V, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + + vperm \V, v21, v22, v17 +.endm + +.macro write_16 V, increment_counter + stvx \V, 0, r7 + +.if \increment_counter + add r7, r7, r8 +.endif +.endm + + .align 2 +;# r3 unsigned char * src +;# r4 int src_pitch +;# r5 int x_offset +;# r6 int y_offset +;# r7 unsigned char * dst +;# r8 int dst_pitch +bilinear_predict16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + HProlog second_pass_16x16_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + hfilter_16 v8, 1 + hfilter_16 v9, 1 + hfilter_16 v10, 1 + hfilter_16 v11, 1 + hfilter_16 v12, 1 + hfilter_16 v13, 1 + hfilter_16 v14, 1 + hfilter_16 v15, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq store_out_16x16_b + + hfilter_16 v16, 0 + + b second_pass_16x16_b + +second_pass_16x16_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, 1 + load_and_align_16 v1, 1 + load_and_align_16 v2, 1 + load_and_align_16 v3, 1 + load_and_align_16 v4, 1 + load_and_align_16 v5, 1 + load_and_align_16 v6, 1 + load_and_align_16 v7, 1 + load_and_align_16 v8, 1 + load_and_align_16 v9, 1 + load_and_align_16 v10, 1 + load_and_align_16 v11, 1 + load_and_align_16 v12, 1 + load_and_align_16 v13, 1 + load_and_align_16 v14, 1 + load_and_align_16 v15, 1 + load_and_align_16 v16, 0 + +second_pass_16x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +store_out_16x16_b: + + write_16 v0, 1 + write_16 v1, 1 + write_16 v2, 1 + write_16 v3, 1 + write_16 v4, 1 + write_16 v5, 1 + write_16 v6, 1 + write_16 v7, 1 + write_16 v8, 1 + write_16 v9, 1 + write_16 v10, 1 + write_16 v11, 1 + write_16 v12, 1 + write_16 v13, 1 + write_16 v14, 1 + write_16 v15, 0 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +hfilter_b: + .byte 128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0 + .byte 112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0 + .byte 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0 + .byte 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0 + .byte 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0 + .byte 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0 + .byte 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0 + .byte 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0 + + .align 4 +vfilter_b: + .byte 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + + .align 4 +b_hperm_b: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +b_0123_b: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +b_4567_b: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + +b_hilo_b: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23
diff --git a/vp8/common/ppc/idctllm_altivec.asm b/vp8/common/ppc/idctllm_altivec.asm new file mode 100644 index 0000000..e88af8d --- /dev/null +++ b/vp8/common/ppc/idctllm_altivec.asm
@@ -0,0 +1,188 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl short_idct4x4llm_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +;# r3 short *input +;# r4 short *output +;# r5 int pitch + .align 2 +short_idct4x4llm_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + load_c v8, sinpi8sqrt2, 0, r9, r10 + load_c v9, cospi8sqrt2minus1, 0, r9, r10 + load_c v10, hi_hi, 0, r9, r10 + load_c v11, lo_lo, 0, r9, r10 + load_c v12, shift_16, 0, r9, r10 + + li r10, 16 + lvx v0, 0, r3 ;# input ip[0], ip[ 4] + lvx v1, r10, r3 ;# input ip[8], ip[12] + + ;# first pass + vupkhsh v2, v0 + vupkhsh v3, v1 + vaddsws v6, v2, v3 ;# a1 = ip[0]+ip[8] + vsubsws v7, v2, v3 ;# b1 = ip[0]-ip[8] + + vupklsh v0, v0 + vmulosh v4, v0, v8 + vsraw v4, v4, v12 + vaddsws v4, v4, v0 ;# ip[ 4] * sin(pi/8) * sqrt(2) + + vupklsh v1, v1 + vmulosh v5, v1, v9 + vsraw v5, v5, v12 ;# ip[12] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v1 + + vsubsws v4, v4, v5 ;# c1 + + vmulosh v3, v1, v8 + vsraw v3, v3, v12 + vaddsws v3, v3, v1 ;# ip[12] * sin(pi/8) * sqrt(2) + + vmulosh v5, v0, v9 + vsraw v5, v5, v12 ;# ip[ 4] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v0 + + vaddsws v3, v3, v5 ;# d1 + + vaddsws v0, v6, v3 ;# a1 + d1 + vsubsws v3, v6, v3 ;# a1 - d1 + + vaddsws v1, v7, v4 ;# b1 + c1 + vsubsws v2, v7, v4 ;# b1 - c1 + + ;# transpose input + vmrghw v4, v0, v1 ;# a0 b0 a1 b1 + vmrghw v5, v2, v3 ;# c0 d0 c1 d1 + + vmrglw v6, v0, v1 ;# a2 b2 a3 b3 + vmrglw v7, v2, v3 ;# c2 d2 c3 d3 + + vperm v0, v4, v5, v10 ;# a0 b0 c0 d0 + vperm v1, v4, v5, v11 ;# a1 b1 c1 d1 + + vperm v2, v6, v7, v10 ;# a2 b2 c2 d2 + vperm v3, v6, v7, v11 ;# a3 b3 c3 d3 + + ;# second pass + vaddsws v6, v0, v2 ;# a1 = ip[0]+ip[8] + vsubsws v7, v0, v2 ;# b1 = ip[0]-ip[8] + + vmulosh v4, v1, v8 + vsraw v4, v4, v12 + vaddsws v4, v4, v1 ;# ip[ 4] * sin(pi/8) * sqrt(2) + + vmulosh v5, v3, v9 + vsraw v5, v5, v12 ;# ip[12] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v3 + + vsubsws v4, v4, v5 ;# c1 + + vmulosh v2, v3, v8 + vsraw v2, v2, v12 + vaddsws v2, v2, v3 ;# ip[12] * sin(pi/8) * sqrt(2) + + vmulosh v5, v1, v9 + vsraw v5, v5, v12 ;# ip[ 4] * cos(pi/8) * sqrt(2) + vaddsws v5, v5, v1 + + vaddsws v3, v2, v5 ;# d1 + + vaddsws v0, v6, v3 ;# a1 + d1 + vsubsws v3, v6, v3 ;# a1 - d1 + + vaddsws v1, v7, v4 ;# b1 + c1 + vsubsws v2, v7, v4 ;# b1 - c1 + + vspltish v6, 4 + vspltish v7, 3 + + vpkswss v0, v0, v1 + vpkswss v1, v2, v3 + + vaddshs v0, v0, v6 + vaddshs v1, v1, v6 + + vsrah v0, v0, v7 + vsrah v1, v1, v7 + + ;# transpose output + vmrghh v2, v0, v1 ;# a0 c0 a1 c1 a2 c2 a3 c3 + vmrglh v3, v0, v1 ;# b0 d0 b1 d1 b2 d2 b3 d3 + + vmrghh v0, v2, v3 ;# a0 b0 c0 d0 a1 b1 c1 d1 + vmrglh v1, v2, v3 ;# a2 b2 c2 d2 a3 b3 c3 d3 + + stwu r1,-416(r1) ;# create space on the stack + + stvx v0, 0, r1 + lwz r6, 0(r1) + stw r6, 0(r4) + lwz r6, 4(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + lwz r6, 8(r1) + stw r6, 0(r4) + lwz r6, 12(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + stvx v1, 0, r1 + lwz r6, 0(r1) + stw r6, 0(r4) + lwz r6, 4(r1) + stw r6, 4(r4) + + add r4, r4, r5 + + lwz r6, 8(r1) + stw r6, 0(r4) + lwz r6, 12(r1) + stw r6, 4(r4) + + addi r1, r1, 416 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 4 +sinpi8sqrt2: + .short 35468, 35468, 35468, 35468, 35468, 35468, 35468, 35468 + + .align 4 +cospi8sqrt2minus1: + .short 20091, 20091, 20091, 20091, 20091, 20091, 20091, 20091 + + .align 4 +shift_16: + .long 16, 16, 16, 16 + + .align 4 +hi_hi: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23 + + .align 4 +lo_lo: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31
diff --git a/vp8/common/ppc/loopfilter_altivec.c b/vp8/common/ppc/loopfilter_altivec.c new file mode 100644 index 0000000..586eed4 --- /dev/null +++ b/vp8/common/ppc/loopfilter_altivec.c
@@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "loopfilter.h" +#include "onyxc_int.h" + +typedef void loop_filter_function_y_ppc +( + unsigned char *s, // source pointer + int p, // pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh +); + +typedef void loop_filter_function_uv_ppc +( + unsigned char *u, // source pointer + unsigned char *v, // source pointer + int p, // pitch + const signed char *flimit, + const signed char *limit, + const signed char *thresh +); + +typedef void loop_filter_function_s_ppc +( + unsigned char *s, // source pointer + int p, // pitch + const signed char *flimit +); + +loop_filter_function_y_ppc mbloop_filter_horizontal_edge_y_ppc; +loop_filter_function_y_ppc mbloop_filter_vertical_edge_y_ppc; +loop_filter_function_y_ppc loop_filter_horizontal_edge_y_ppc; +loop_filter_function_y_ppc loop_filter_vertical_edge_y_ppc; + +loop_filter_function_uv_ppc mbloop_filter_horizontal_edge_uv_ppc; +loop_filter_function_uv_ppc mbloop_filter_vertical_edge_uv_ppc; +loop_filter_function_uv_ppc loop_filter_horizontal_edge_uv_ppc; +loop_filter_function_uv_ppc loop_filter_vertical_edge_uv_ppc; + +loop_filter_function_s_ppc loop_filter_simple_horizontal_edge_ppc; +loop_filter_function_s_ppc loop_filter_simple_vertical_edge_ppc; + +// Horizontal MB filtering +void loop_filter_mbh_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + mbloop_filter_horizontal_edge_y_ppc(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr); + + if (u_ptr) + mbloop_filter_horizontal_edge_uv_ppc(u_ptr, v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr); +} + +void loop_filter_mbhs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_horizontal_edge_ppc(y_ptr, y_stride, lfi->mbflim); +} + +// Vertical MB Filtering +void loop_filter_mbv_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + mbloop_filter_vertical_edge_y_ppc(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr); + + if (u_ptr) + mbloop_filter_vertical_edge_uv_ppc(u_ptr, v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr); +} + +void loop_filter_mbvs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_vertical_edge_ppc(y_ptr, y_stride, lfi->mbflim); +} + +// Horizontal B Filtering +void loop_filter_bh_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + // These should all be done at once with one call, instead of 3 + loop_filter_horizontal_edge_y_ppc(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + loop_filter_horizontal_edge_y_ppc(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + loop_filter_horizontal_edge_y_ppc(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr); + + if (u_ptr) + loop_filter_horizontal_edge_uv_ppc(u_ptr + 4 * uv_stride, v_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr); +} + +void loop_filter_bhs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_horizontal_edge_ppc(y_ptr + 4 * y_stride, y_stride, lfi->flim); + loop_filter_simple_horizontal_edge_ppc(y_ptr + 8 * y_stride, y_stride, lfi->flim); + loop_filter_simple_horizontal_edge_ppc(y_ptr + 12 * y_stride, y_stride, lfi->flim); +} + +// Vertical B Filtering +void loop_filter_bv_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + loop_filter_vertical_edge_y_ppc(y_ptr, y_stride, lfi->flim, lfi->lim, lfi->thr); + + if (u_ptr) + loop_filter_vertical_edge_uv_ppc(u_ptr + 4, v_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr); +} + +void loop_filter_bvs_ppc(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void)simpler_lpf; + (void)u_ptr; + (void)v_ptr; + (void)uv_stride; + loop_filter_simple_vertical_edge_ppc(y_ptr + 4, y_stride, lfi->flim); + loop_filter_simple_vertical_edge_ppc(y_ptr + 8, y_stride, lfi->flim); + loop_filter_simple_vertical_edge_ppc(y_ptr + 12, y_stride, lfi->flim); +}
diff --git a/vp8/common/ppc/loopfilter_filters_altivec.asm b/vp8/common/ppc/loopfilter_filters_altivec.asm new file mode 100644 index 0000000..78a5cf9 --- /dev/null +++ b/vp8/common/ppc/loopfilter_filters_altivec.asm
@@ -0,0 +1,1252 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl mbloop_filter_horizontal_edge_y_ppc + .globl loop_filter_horizontal_edge_y_ppc + .globl mbloop_filter_vertical_edge_y_ppc + .globl loop_filter_vertical_edge_y_ppc + + .globl mbloop_filter_horizontal_edge_uv_ppc + .globl loop_filter_horizontal_edge_uv_ppc + .globl mbloop_filter_vertical_edge_uv_ppc + .globl loop_filter_vertical_edge_uv_ppc + + .globl loop_filter_simple_horizontal_edge_ppc + .globl loop_filter_simple_vertical_edge_ppc + + .text +;# We often need to perform transposes (and other transpose-like operations) +;# on matrices of data. This is simplified by the fact that we usually +;# operate on hunks of data whose dimensions are powers of 2, or at least +;# divisible by highish powers of 2. +;# +;# These operations can be very confusing. They become more straightforward +;# when we think of them as permutations of address bits: Concatenate a +;# group of vector registers and think of it as occupying a block of +;# memory beginning at address zero. The low four bits 0...3 of the +;# address then correspond to position within a register, the higher-order +;# address bits select the register. +;# +;# Although register selection, at the code level, is arbitrary, things +;# are simpler if we use contiguous ranges of register numbers, simpler +;# still if the low-order bits of the register number correspond to +;# conceptual address bits. We do this whenever reasonable. +;# +;# A 16x16 transpose can then be thought of as an operation on +;# a 256-element block of memory. It takes 8 bits 0...7 to address this +;# memory and the effect of a transpose is to interchange address bit +;# 0 with 4, 1 with 5, 2 with 6, and 3 with 7. Bits 0...3 index the +;# column, which is interchanged with the row addressed by bits 4..7. +;# +;# The altivec merge instructions provide a rapid means of effecting +;# many of these transforms. They operate at three widths (8,16,32). +;# Writing V(x) for vector register #x, paired merges permute address +;# indices as follows. +;# +;# 0->1 1->2 2->3 3->(4+d) (4+s)->0: +;# +;# vmrghb V( x), V( y), V( y + (1<<s)) +;# vmrglb V( x + (1<<d)), V( y), V( y + (1<<s)) +;# +;# +;# =0= 1->2 2->3 3->(4+d) (4+s)->1: +;# +;# vmrghh V( x), V( y), V( y + (1<<s)) +;# vmrglh V( x + (1<<d)), V( y), V( y + (1<<s)) +;# +;# +;# =0= =1= 2->3 3->(4+d) (4+s)->2: +;# +;# vmrghw V( x), V( y), V( y + (1<<s)) +;# vmrglw V( x + (1<<d)), V( y), V( y + (1<<s)) +;# +;# +;# Unfortunately, there is no doubleword merge instruction. +;# The following sequence uses "vperm" is a substitute. +;# Assuming that the selection masks b_hihi and b_lolo (defined in LFppc.c) +;# are in registers Vhihi and Vlolo, we can also effect the permutation +;# +;# =0= =1= =2= 3->(4+d) (4+s)->3 by the sequence: +;# +;# vperm V( x), V( y), V( y + (1<<s)), Vhihi +;# vperm V( x + (1<<d)), V( y), V( y + (1<<s)), Vlolo +;# +;# +;# Except for bits s and d, the other relationships between register +;# number (= high-order part of address) bits are at the disposal of +;# the programmer. +;# + +;# To avoid excess transposes, we filter all 3 vertical luma subblock +;# edges together. This requires a single 16x16 transpose, which, in +;# the above language, amounts to the following permutation of address +;# indices: 0<->4 1<->5 2<->6 3<->7, which we accomplish by +;# 4 iterations of the cyclic transform 0->1->2->3->4->5->6->7->0. +;# +;# Except for the fact that the destination registers get written +;# before we are done referencing the old contents, the cyclic transform +;# is effected by +;# +;# x = 0; do { +;# vmrghb V(2x), V(x), V(x+8); +;# vmrghb V(2x+1), V(x), V(x+8); +;# } while( ++x < 8); +;# +;# For clarity, and because we can afford it, we do this transpose +;# using all 32 registers, alternating the banks 0..15 and 16 .. 31, +;# leaving the final result in 16 .. 31, as the lower registers are +;# used in the filtering itself. +;# +.macro Tpair A, B, X, Y + vmrghb \A, \X, \Y + vmrglb \B, \X, \Y +.endm + +;# Each step takes 8*2 = 16 instructions + +.macro t16_even + Tpair v16,v17, v0,v8 + Tpair v18,v19, v1,v9 + Tpair v20,v21, v2,v10 + Tpair v22,v23, v3,v11 + Tpair v24,v25, v4,v12 + Tpair v26,v27, v5,v13 + Tpair v28,v29, v6,v14 + Tpair v30,v31, v7,v15 +.endm + +.macro t16_odd + Tpair v0,v1, v16,v24 + Tpair v2,v3, v17,v25 + Tpair v4,v5, v18,v26 + Tpair v6,v7, v19,v27 + Tpair v8,v9, v20,v28 + Tpair v10,v11, v21,v29 + Tpair v12,v13, v22,v30 + Tpair v14,v15, v23,v31 +.endm + +;# Whole transpose takes 4*16 = 64 instructions + +.macro t16_full + t16_odd + t16_even + t16_odd + t16_even +.endm + +;# Vertical edge filtering requires transposes. For the simple filter, +;# we need to convert 16 rows of 4 pels each into 4 registers of 16 pels +;# each. Writing 0 ... 63 for the pixel indices, the desired result is: +;# +;# v0 = 0 1 ... 14 15 +;# v1 = 16 17 ... 30 31 +;# v2 = 32 33 ... 47 48 +;# v3 = 49 50 ... 62 63 +;# +;# In frame-buffer memory, the layout is: +;# +;# 0 16 32 48 +;# 1 17 33 49 +;# ... +;# 15 31 47 63. +;# +;# We begin by reading the data 32 bits at a time (using scalar operations) +;# into a temporary array, reading the rows of the array into vector registers, +;# with the following layout: +;# +;# v0 = 0 16 32 48 4 20 36 52 8 24 40 56 12 28 44 60 +;# v1 = 1 17 33 49 5 21 ... 45 61 +;# v2 = 2 18 ... 46 62 +;# v3 = 3 19 ... 47 63 +;# +;# From the "address-bit" perspective discussed above, we simply need to +;# interchange bits 0 <-> 4 and 1 <-> 5, leaving bits 2 and 3 alone. +;# In other words, we transpose each of the four 4x4 submatrices. +;# +;# This transformation is its own inverse, and we need to perform it +;# again before writing the pixels back into the frame buffer. +;# +;# It acts in place on registers v0...v3, uses v4...v7 as temporaries, +;# and assumes that v14/v15 contain the b_hihi/b_lolo selectors +;# defined above. We think of both groups of 4 registers as having +;# "addresses" {0,1,2,3} * 16. +;# +.macro Transpose4times4x4 Vlo, Vhi + + ;# d=s=0 0->1 1->2 2->3 3->4 4->0 =5= + + vmrghb v4, v0, v1 + vmrglb v5, v0, v1 + vmrghb v6, v2, v3 + vmrglb v7, v2, v3 + + ;# d=0 s=1 =0= 1->2 2->3 3->4 4->5 5->1 + + vmrghh v0, v4, v6 + vmrglh v1, v4, v6 + vmrghh v2, v5, v7 + vmrglh v3, v5, v7 + + ;# d=s=0 =0= =1= 2->3 3->4 4->2 =5= + + vmrghw v4, v0, v1 + vmrglw v5, v0, v1 + vmrghw v6, v2, v3 + vmrglw v7, v2, v3 + + ;# d=0 s=1 =0= =1= =2= 3->4 4->5 5->3 + + vperm v0, v4, v6, \Vlo + vperm v1, v4, v6, \Vhi + vperm v2, v5, v7, \Vlo + vperm v3, v5, v7, \Vhi +.endm +;# end Transpose4times4x4 + + +;# Normal mb vertical edge filter transpose. +;# +;# We read 8 columns of data, initially in the following pattern: +;# +;# (0,0) (1,0) ... (7,0) (0,1) (1,1) ... (7,1) +;# (0,2) (1,2) ... (7,2) (0,3) (1,3) ... (7,3) +;# ... +;# (0,14) (1,14) .. (7,14) (0,15) (1,15) .. (7,15) +;# +;# and wish to convert to: +;# +;# (0,0) ... (0,15) +;# (1,0) ... (1,15) +;# ... +;# (7,0) ... (7,15). +;# +;# In "address bit" language, we wish to map +;# +;# 0->4 1->5 2->6 3->0 4->1 5->2 6->3, i.e., I -> (I+4) mod 7. +;# +;# This can be accomplished by 4 iterations of the cyclic transform +;# +;# I -> (I+1) mod 7; +;# +;# each iteration can be realized by (d=0, s=2): +;# +;# x = 0; do Tpair( V(2x),V(2x+1), V(x),V(x+4)) while( ++x < 4); +;# +;# The input/output is in registers v0...v7. We use v10...v17 as mirrors; +;# preserving v8 = sign converter. +;# +;# Inverse transpose is similar, except here I -> (I+3) mod 7 and the +;# result lands in the "mirror" registers v10...v17 +;# +.macro t8x16_odd + Tpair v10, v11, v0, v4 + Tpair v12, v13, v1, v5 + Tpair v14, v15, v2, v6 + Tpair v16, v17, v3, v7 +.endm + +.macro t8x16_even + Tpair v0, v1, v10, v14 + Tpair v2, v3, v11, v15 + Tpair v4, v5, v12, v16 + Tpair v6, v7, v13, v17 +.endm + +.macro transpose8x16_fwd + t8x16_odd + t8x16_even + t8x16_odd + t8x16_even +.endm + +.macro transpose8x16_inv + t8x16_odd + t8x16_even + t8x16_odd +.endm + +.macro Transpose16x16 + vmrghb v0, v16, v24 + vmrglb v1, v16, v24 + vmrghb v2, v17, v25 + vmrglb v3, v17, v25 + vmrghb v4, v18, v26 + vmrglb v5, v18, v26 + vmrghb v6, v19, v27 + vmrglb v7, v19, v27 + vmrghb v8, v20, v28 + vmrglb v9, v20, v28 + vmrghb v10, v21, v29 + vmrglb v11, v21, v29 + vmrghb v12, v22, v30 + vmrglb v13, v22, v30 + vmrghb v14, v23, v31 + vmrglb v15, v23, v31 + vmrghb v16, v0, v8 + vmrglb v17, v0, v8 + vmrghb v18, v1, v9 + vmrglb v19, v1, v9 + vmrghb v20, v2, v10 + vmrglb v21, v2, v10 + vmrghb v22, v3, v11 + vmrglb v23, v3, v11 + vmrghb v24, v4, v12 + vmrglb v25, v4, v12 + vmrghb v26, v5, v13 + vmrglb v27, v5, v13 + vmrghb v28, v6, v14 + vmrglb v29, v6, v14 + vmrghb v30, v7, v15 + vmrglb v31, v7, v15 + vmrghb v0, v16, v24 + vmrglb v1, v16, v24 + vmrghb v2, v17, v25 + vmrglb v3, v17, v25 + vmrghb v4, v18, v26 + vmrglb v5, v18, v26 + vmrghb v6, v19, v27 + vmrglb v7, v19, v27 + vmrghb v8, v20, v28 + vmrglb v9, v20, v28 + vmrghb v10, v21, v29 + vmrglb v11, v21, v29 + vmrghb v12, v22, v30 + vmrglb v13, v22, v30 + vmrghb v14, v23, v31 + vmrglb v15, v23, v31 + vmrghb v16, v0, v8 + vmrglb v17, v0, v8 + vmrghb v18, v1, v9 + vmrglb v19, v1, v9 + vmrghb v20, v2, v10 + vmrglb v21, v2, v10 + vmrghb v22, v3, v11 + vmrglb v23, v3, v11 + vmrghb v24, v4, v12 + vmrglb v25, v4, v12 + vmrghb v26, v5, v13 + vmrglb v27, v5, v13 + vmrghb v28, v6, v14 + vmrglb v29, v6, v14 + vmrghb v30, v7, v15 + vmrglb v31, v7, v15 +.endm + +;# load_g loads a global vector (whose address is in the local variable Gptr) +;# into vector register Vreg. Trashes r0 +.macro load_g Vreg, Gptr + lwz r0, \Gptr + lvx \Vreg, 0, r0 +.endm + +;# exploit the saturation here. if the answer is negative +;# it will be clamped to 0. orring 0 with a positive +;# number will be the positive number (abs) +;# RES = abs( A-B), trashes TMP +.macro Abs RES, TMP, A, B + vsububs \RES, \A, \B + vsububs \TMP, \B, \A + vor \RES, \RES, \TMP +.endm + +;# RES = Max( RES, abs( A-B)), trashes TMP +.macro max_abs RES, TMP, A, B + vsububs \TMP, \A, \B + vmaxub \RES, \RES, \TMP + vsububs \TMP, \B, \A + vmaxub \RES, \RES, \TMP +.endm + +.macro Masks + ;# build masks + ;# input is all 8 bit unsigned (0-255). need to + ;# do abs(vala-valb) > limit. but no need to compare each + ;# value to the limit. find the max of the absolute differences + ;# and compare that to the limit. + ;# First hev + Abs v14, v13, v2, v3 ;# |P1 - P0| + max_abs v14, v13, v5, v4 ;# |Q1 - Q0| + + vcmpgtub v10, v14, v10 ;# HEV = true if thresh exceeded + + ;# Next limit + max_abs v14, v13, v0, v1 ;# |P3 - P2| + max_abs v14, v13, v1, v2 ;# |P2 - P1| + max_abs v14, v13, v6, v5 ;# |Q2 - Q1| + max_abs v14, v13, v7, v6 ;# |Q3 - Q2| + + vcmpgtub v9, v14, v9 ;# R = true if limit exceeded + + ;# flimit + Abs v14, v13, v3, v4 ;# |P0 - Q0| + + vcmpgtub v8, v14, v8 ;# X = true if flimit exceeded + + vor v8, v8, v9 ;# R = true if flimit or limit exceeded + ;# done building masks +.endm + +.macro build_constants RFL, RLI, RTH, FL, LI, TH + ;# build constants + lvx \FL, 0, \RFL ;# flimit + lvx \LI, 0, \RLI ;# limit + lvx \TH, 0, \RTH ;# thresh + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 +.endm + +.macro load_data_y + ;# setup strides/pointers to be able to access + ;# all of the data + add r5, r4, r4 ;# r5 = 2 * stride + sub r6, r3, r5 ;# r6 -> 2 rows back + neg r7, r4 ;# r7 = -stride + + ;# load 16 pixels worth of data to work on + sub r0, r6, r5 ;# r0 -> 4 rows back (temp) + lvx v0, 0, r0 ;# P3 (read only) + lvx v1, r7, r6 ;# P2 + lvx v2, 0, r6 ;# P1 + lvx v3, r7, r3 ;# P0 + lvx v4, 0, r3 ;# Q0 + lvx v5, r4, r3 ;# Q1 + lvx v6, r5, r3 ;# Q2 + add r0, r3, r5 ;# r0 -> 2 rows fwd (temp) + lvx v7, r4, r0 ;# Q3 (read only) +.endm + +;# Expects +;# v10 == HEV +;# v13 == tmp +;# v14 == tmp +.macro common_adjust P0, Q0, P1, Q1, HEV_PRESENT + vxor \P1, \P1, v11 ;# SP1 + vxor \P0, \P0, v11 ;# SP0 + vxor \Q0, \Q0, v11 ;# SQ0 + vxor \Q1, \Q1, v11 ;# SQ1 + + vsubsbs v13, \P1, \Q1 ;# f = c (P1 - Q1) +.if \HEV_PRESENT + vand v13, v13, v10 ;# f &= hev +.endif + vsubsbs v14, \Q0, \P0 ;# -126 <= X = Q0-P0 <= +126 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + + vandc v13, v13, v8 ;# f &= mask + + vspltisb v8, 3 + vspltisb v9, 4 + + vaddsbs v14, v13, v9 ;# f1 = c (f+4) + vaddsbs v15, v13, v8 ;# f2 = c (f+3) + + vsrab v13, v14, v8 ;# f1 >>= 3 + vsrab v15, v15, v8 ;# f2 >>= 3 + + vsubsbs \Q0, \Q0, v13 ;# u1 = c (SQ0 - f1) + vaddsbs \P0, \P0, v15 ;# u2 = c (SP0 + f2) +.endm + +.macro vp8_mbfilter + Masks + + ;# start the fitering here + vxor v1, v1, v11 ;# SP2 + vxor v2, v2, v11 ;# SP1 + vxor v3, v3, v11 ;# SP0 + vxor v4, v4, v11 ;# SQ0 + vxor v5, v5, v11 ;# SQ1 + vxor v6, v6, v11 ;# SQ2 + + ;# add outer taps if we have high edge variance + vsubsbs v13, v2, v5 ;# f = c (SP1-SQ1) + + vsubsbs v14, v4, v3 ;# SQ0-SP0 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 + vaddsbs v13, v13, v14 ;# f = c( c(SP1-SQ1) + 3*(SQ0-SP0)) + + vandc v13, v13, v8 ;# f &= mask + vand v15, v13, v10 ;# f2 = f & hev + + ;# save bottom 3 bits so that we round one side +4 and the other +3 + vspltisb v8, 3 + vspltisb v9, 4 + + vaddsbs v14, v15, v9 ;# f1 = c (f+4) + vaddsbs v15, v15, v8 ;# f2 = c (f+3) + + vsrab v14, v14, v8 ;# f1 >>= 3 + vsrab v15, v15, v8 ;# f2 >>= 3 + + vsubsbs v4, v4, v14 ;# u1 = c (SQ0 - f1) + vaddsbs v3, v3, v15 ;# u2 = c (SP0 + f2) + + ;# only apply wider filter if not high edge variance + vandc v13, v13, v10 ;# f &= ~hev + + vspltisb v9, 2 + vnor v8, v8, v8 + vsrb v9, v8, v9 ;# 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f + vupkhsb v9, v9 ;# 0x003f003f003f003f003f003f003f003f + vspltisb v8, 9 + + ;# roughly 1/7th difference across boundary + vspltish v10, 7 + vmulosb v14, v8, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v8, v13 + vaddshs v14, v14, v9 ;# += 63 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v6, v6, v10 ;# subtract from Q and add to P + vaddsbs v1, v1, v10 + + vxor v6, v6, v11 + vxor v1, v1, v11 + + ;# roughly 2/7th difference across boundary + vspltish v10, 7 + vaddubm v12, v8, v8 + vmulosb v14, v12, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v12, v13 + vaddshs v14, v14, v9 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v5, v5, v10 ;# subtract from Q and add to P + vaddsbs v2, v2, v10 + + vxor v5, v5, v11 + vxor v2, v2, v11 + + ;# roughly 3/7th difference across boundary + vspltish v10, 7 + vaddubm v12, v12, v8 + vmulosb v14, v12, v13 ;# A = c( c(P1-Q1) + 3*(Q0-P0)) + vmulesb v15, v12, v13 + vaddshs v14, v14, v9 + vaddshs v15, v15, v9 + vsrah v14, v14, v10 ;# >>= 7 + vsrah v15, v15, v10 + vmrglh v10, v15, v14 + vmrghh v15, v15, v14 + + vpkshss v10, v15, v10 ;# X = saturated down to bytes + + vsubsbs v4, v4, v10 ;# subtract from Q and add to P + vaddsbs v3, v3, v10 + + vxor v4, v4, v11 + vxor v3, v3, v11 +.endm + +.macro SBFilter + Masks + + common_adjust v3, v4, v2, v5, 1 + + ;# outer tap adjustments + vspltisb v8, 1 + + vaddubm v13, v13, v8 ;# f += 1 + vsrab v13, v13, v8 ;# f >>= 1 + + vandc v13, v13, v10 ;# f &= ~hev + + vsubsbs v5, v5, v13 ;# u1 = c (SQ1 - f) + vaddsbs v2, v2, v13 ;# u2 = c (SP1 + f) + + vxor v2, v2, v11 + vxor v3, v3, v11 + vxor v4, v4, v11 + vxor v5, v5, v11 +.endm + + .align 2 +mbloop_filter_horizontal_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r5, r6, r7, v8, v9, v10 + + load_data_y + + vp8_mbfilter + + stvx v1, r7, r6 ;# P2 + stvx v2, 0, r6 ;# P1 + stvx v3, r7, r3 ;# P0 + stvx v4, 0, r3 ;# Q0 + stvx v5, r4, r3 ;# Q1 + stvx v6, r5, r3 ;# Q2 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +loop_filter_horizontal_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r5, r6, r7, v8, v9, v10 + + load_data_y + + SBFilter + + stvx v2, 0, r6 ;# P1 + stvx v3, r7, r3 ;# P0 + stvx v4, 0, r3 ;# Q0 + stvx v5, r4, r3 ;# Q1 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# Filtering a vertical mb. Each mb is aligned on a 16 byte boundary. +;# So we can read in an entire mb aligned. However if we want to filter the mb +;# edge we run into problems. For the loopfilter we require 4 bytes before the mb +;# and 4 after for a total of 8 bytes. Reading 16 bytes inorder to get 4 is a bit +;# of a waste. So this is an even uglier way to get around that. +;# Using the regular register file words are read in and then saved back out to +;# memory to align and order them up. Then they are read in using the +;# vector register file. +.macro RLVmb V, R + lwzux r0, r3, r4 + stw r0, 4(\R) + lwz r0,-4(r3) + stw r0, 0(\R) + lwzux r0, r3, r4 + stw r0,12(\R) + lwz r0,-4(r3) + stw r0, 8(\R) + lvx \V, 0, \R +.endm + +.macro WLVmb V, R + stvx \V, 0, \R + lwz r0,12(\R) + stwux r0, r3, r4 + lwz r0, 8(\R) + stw r0,-4(r3) + lwz r0, 4(\R) + stwux r0, r3, r4 + lwz r0, 0(\R) + stw r0,-4(r3) +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +mbloop_filter_vertical_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + sub r3, r3, r4 + + RLVmb v0, r9 + RLVmb v1, r9 + RLVmb v2, r9 + RLVmb v3, r9 + RLVmb v4, r9 + RLVmb v5, r9 + RLVmb v6, r9 + RLVmb v7, r9 + + transpose8x16_fwd + + build_constants r5, r6, r7, v8, v9, v10 + + vp8_mbfilter + + transpose8x16_inv + + add r3, r3, r4 + neg r4, r4 + + WLVmb v17, r9 + WLVmb v16, r9 + WLVmb v15, r9 + WLVmb v14, r9 + WLVmb v13, r9 + WLVmb v12, r9 + WLVmb v11, r9 + WLVmb v10, r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro RL V, R, P + lvx \V, 0, \R + add \R, \R, \P +.endm + +.macro WL V, R, P + stvx \V, 0, \R + add \R, \R, \P +.endm + +.macro Fil P3, P2, P1, P0, Q0, Q1, Q2, Q3 + ;# K = |P0-P1| already + Abs v14, v13, \Q0, \Q1 ;# M = |Q0-Q1| + vmaxub v14, v14, v4 ;# M = max( |P0-P1|, |Q0-Q1|) + vcmpgtub v10, v14, v0 + + Abs v4, v5, \Q2, \Q3 ;# K = |Q2-Q3| = next |P0-P1] + + max_abs v14, v13, \Q1, \Q2 ;# M = max( M, |Q1-Q2|) + max_abs v14, v13, \P1, \P2 ;# M = max( M, |P1-P2|) + max_abs v14, v13, \P2, \P3 ;# M = max( M, |P2-P3|) + + vmaxub v14, v14, v4 ;# M = max interior abs diff + vcmpgtub v9, v14, v2 ;# M = true if int_l exceeded + + Abs v14, v13, \P0, \Q0 ;# X = Abs( P0-Q0) + vcmpgtub v8, v14, v3 ;# X = true if edge_l exceeded + vor v8, v8, v9 ;# M = true if edge_l or int_l exceeded + + ;# replace P1,Q1 w/signed versions + common_adjust \P0, \Q0, \P1, \Q1, 1 + + vaddubm v13, v13, v1 ;# -16 <= M <= 15, saturation irrelevant + vsrab v13, v13, v1 + vandc v13, v13, v10 ;# adjust P1,Q1 by (M+1)>>1 if ! hev + vsubsbs \Q1, \Q1, v13 + vaddsbs \P1, \P1, v13 + + vxor \P1, \P1, v11 ;# P1 + vxor \P0, \P0, v11 ;# P0 + vxor \Q0, \Q0, v11 ;# Q0 + vxor \Q1, \Q1, v11 ;# Q1 +.endm + + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +;# r6 const signed char *limit +;# r7 const signed char *thresh +loop_filter_vertical_edge_y_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + addi r9, r3, 0 + RL v16, r9, r4 + RL v17, r9, r4 + RL v18, r9, r4 + RL v19, r9, r4 + RL v20, r9, r4 + RL v21, r9, r4 + RL v22, r9, r4 + RL v23, r9, r4 + RL v24, r9, r4 + RL v25, r9, r4 + RL v26, r9, r4 + RL v27, r9, r4 + RL v28, r9, r4 + RL v29, r9, r4 + RL v30, r9, r4 + lvx v31, 0, r9 + + Transpose16x16 + + vspltisb v1, 1 + + build_constants r5, r6, r7, v3, v2, v0 + + Abs v4, v5, v19, v18 ;# K(v14) = first |P0-P1| + + Fil v16, v17, v18, v19, v20, v21, v22, v23 + Fil v20, v21, v22, v23, v24, v25, v26, v27 + Fil v24, v25, v26, v27, v28, v29, v30, v31 + + Transpose16x16 + + addi r9, r3, 0 + WL v16, r9, r4 + WL v17, r9, r4 + WL v18, r9, r4 + WL v19, r9, r4 + WL v20, r9, r4 + WL v21, r9, r4 + WL v22, r9, r4 + WL v23, r9, r4 + WL v24, r9, r4 + WL v25, r9, r4 + WL v26, r9, r4 + WL v27, r9, r4 + WL v28, r9, r4 + WL v29, r9, r4 + WL v30, r9, r4 + stvx v31, 0, r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- UV FILTERING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +.macro active_chroma_sel V + andi. r7, r3, 8 ;# row origin modulo 16 + add r7, r7, r7 ;# selects selectors + lis r12, _chromaSelectors@ha + la r0, _chromaSelectors@l(r12) + lwzux r0, r7, r0 ;# leave selector addr in r7 + + lvx \V, 0, r0 ;# mask to concatenate active U,V pels +.endm + +.macro hread_uv Dest, U, V, Offs, VMask + lvx \U, \Offs, r3 + lvx \V, \Offs, r4 + vperm \Dest, \U, \V, \VMask ;# Dest = active part of U then V +.endm + +.macro hwrite_uv New, U, V, Offs, Umask, Vmask + vperm \U, \New, \U, \Umask ;# Combine new pels with siblings + vperm \V, \New, \V, \Vmask + stvx \U, \Offs, r3 ;# Write to frame buffer + stvx \V, \Offs, r4 +.endm + +;# Process U,V in parallel. +.macro load_chroma_h + neg r9, r5 ;# r9 = -1 * stride + add r8, r9, r9 ;# r8 = -2 * stride + add r10, r5, r5 ;# r10 = 2 * stride + + active_chroma_sel v12 + + ;# P3, Q3 are read-only; need not save addresses or sibling pels + add r6, r8, r8 ;# r6 = -4 * stride + hread_uv v0, v14, v15, r6, v12 + add r6, r10, r5 ;# r6 = 3 * stride + hread_uv v7, v14, v15, r6, v12 + + ;# Others are read/write; save addresses and sibling pels + + add r6, r8, r9 ;# r6 = -3 * stride + hread_uv v1, v16, v17, r6, v12 + hread_uv v2, v18, v19, r8, v12 + hread_uv v3, v20, v21, r9, v12 + hread_uv v4, v22, v23, 0, v12 + hread_uv v5, v24, v25, r5, v12 + hread_uv v6, v26, v27, r10, v12 +.endm + +.macro uresult_sel V + load_g \V, 4(r7) +.endm + +.macro vresult_sel V + load_g \V, 8(r7) +.endm + +;# always write P1,P0,Q0,Q1 +.macro store_chroma_h + uresult_sel v11 + vresult_sel v12 + hwrite_uv v2, v18, v19, r8, v11, v12 + hwrite_uv v3, v20, v21, r9, v11, v12 + hwrite_uv v4, v22, v23, 0, v11, v12 + hwrite_uv v5, v24, v25, r5, v11, v12 +.endm + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +mbloop_filter_horizontal_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r6, r7, r8, v8, v9, v10 + + load_chroma_h + + vp8_mbfilter + + store_chroma_h + + hwrite_uv v1, v16, v17, r6, v11, v12 ;# v1 == P2 + hwrite_uv v6, v26, v27, r10, v11, v12 ;# v6 == Q2 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +loop_filter_horizontal_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + build_constants r6, r7, r8, v8, v9, v10 + + load_chroma_h + + SBFilter + + store_chroma_h + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro R V, R + lwzux r0, r3, r5 + stw r0, 4(\R) + lwz r0,-4(r3) + stw r0, 0(\R) + lwzux r0, r4, r5 + stw r0,12(\R) + lwz r0,-4(r4) + stw r0, 8(\R) + lvx \V, 0, \R +.endm + + +.macro W V, R + stvx \V, 0, \R + lwz r0,12(\R) + stwux r0, r4, r5 + lwz r0, 8(\R) + stw r0,-4(r4) + lwz r0, 4(\R) + stwux r0, r3, r5 + lwz r0, 0(\R) + stw r0,-4(r3) +.endm + +.macro chroma_vread R + sub r3, r3, r5 ;# back up one line for simplicity + sub r4, r4, r5 + + R v0, \R + R v1, \R + R v2, \R + R v3, \R + R v4, \R + R v5, \R + R v6, \R + R v7, \R + + transpose8x16_fwd +.endm + +.macro chroma_vwrite R + + transpose8x16_inv + + add r3, r3, r5 + add r4, r4, r5 + neg r5, r5 ;# Write rows back in reverse order + + W v17, \R + W v16, \R + W v15, \R + W v14, \R + W v13, \R + W v12, \R + W v11, \R + W v10, \R +.endm + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +mbloop_filter_vertical_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + + chroma_vread r9 + + build_constants r6, r7, r8, v8, v9, v10 + + vp8_mbfilter + + chroma_vwrite r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *u +;# r4 unsigned char *v +;# r5 int p +;# r6 const signed char *flimit +;# r7 const signed char *limit +;# r8 const signed char *thresh +loop_filter_vertical_edge_uv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + la r9, -48(r1) ;# temporary space for reading in vectors + + chroma_vread r9 + + build_constants r6, r7, r8, v8, v9, v10 + + SBFilter + + chroma_vwrite r9 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# -=-=-=-=-=-=-=-=-=-=-=-=-=-= SIMPLE LOOP FILTER =-=-=-=-=-=-=-=-=-=-=-=-=-=- + +.macro vp8_simple_filter + Abs v14, v13, v1, v2 ;# M = abs( P0 - Q0) + vcmpgtub v8, v14, v8 ;# v5 = true if _over_ limit + + ;# preserve unsigned v0 and v3 + common_adjust v1, v2, v0, v3, 0 + + vxor v1, v1, v11 + vxor v2, v2, v11 ;# cvt Q0, P0 back to pels +.endm + +.macro simple_vertical + addi r8, 0, 16 + addi r7, r5, 32 + + lvx v0, 0, r5 + lvx v1, r8, r5 + lvx v2, 0, r7 + lvx v3, r8, r7 + + lis r12, _B_hihi@ha + la r0, _B_hihi@l(r12) + lvx v16, 0, r0 + + lis r12, _B_lolo@ha + la r0, _B_lolo@l(r12) + lvx v17, 0, r0 + + Transpose4times4x4 v16, v17 + vp8_simple_filter + + vxor v0, v0, v11 + vxor v3, v3, v11 ;# cvt Q0, P0 back to pels + + Transpose4times4x4 v16, v17 + + stvx v0, 0, r5 + stvx v1, r8, r5 + stvx v2, 0, r7 + stvx v3, r8, r7 +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +loop_filter_simple_horizontal_edge_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + mtspr 256, r12 ;# set VRSAVE + + ;# build constants + lvx v8, 0, r5 ;# flimit + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 + + neg r5, r4 ;# r5 = -1 * stride + add r6, r5, r5 ;# r6 = -2 * stride + + lvx v0, r6, r3 ;# v0 = P1 = 16 pels two rows above edge + lvx v1, r5, r3 ;# v1 = P0 = 16 pels one row above edge + lvx v2, 0, r3 ;# v2 = Q0 = 16 pels one row below edge + lvx v3, r4, r3 ;# v3 = Q1 = 16 pels two rows below edge + + vp8_simple_filter + + stvx v1, r5, r3 ;# store P0 + stvx v2, 0, r3 ;# store Q0 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +.macro RLV Offs + stw r0, (\Offs*4)(r5) + lwzux r0, r7, r4 +.endm + +.macro WLV Offs + lwz r0, (\Offs*4)(r5) + stwux r0, r7, r4 +.endm + + .align 2 +;# r3 unsigned char *s +;# r4 int p +;# r5 const signed char *flimit +loop_filter_simple_vertical_edge_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xc000 + mtspr 256, r12 ;# set VRSAVE + + ;# build constants + lvx v8, 0, r5 ;# flimit + + vspltisb v11, 8 + vspltisb v12, 4 + vslb v11, v11, v12 ;# 0x80808080808080808080808080808080 + + la r5, -96(r1) ;# temporary space for reading in vectors + + ;# Store 4 pels at word "Offs" in temp array, then advance r7 + ;# to next row and read another 4 pels from the frame buffer. + + subi r7, r3, 2 ;# r7 -> 2 pels before start + lwzx r0, 0, r7 ;# read first 4 pels + + ;# 16 unaligned word accesses + RLV 0 + RLV 4 + RLV 8 + RLV 12 + RLV 1 + RLV 5 + RLV 9 + RLV 13 + RLV 2 + RLV 6 + RLV 10 + RLV 14 + RLV 3 + RLV 7 + RLV 11 + + stw r0, (15*4)(r5) ;# write last 4 pels + + simple_vertical + + ;# Read temp array, write frame buffer. + subi r7, r3, 2 ;# r7 -> 2 pels before start + lwzx r0, 0, r5 ;# read/write first 4 pels + stwx r0, 0, r7 + + WLV 4 + WLV 8 + WLV 12 + WLV 1 + WLV 5 + WLV 9 + WLV 13 + WLV 2 + WLV 6 + WLV 10 + WLV 14 + WLV 3 + WLV 7 + WLV 11 + WLV 15 + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + +_chromaSelectors: + .long _B_hihi + .long _B_Ures0 + .long _B_Vres0 + .long 0 + .long _B_lolo + .long _B_Ures8 + .long _B_Vres8 + .long 0 + + .align 4 +_B_Vres8: + .byte 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15 + + .align 4 +_B_Ures8: + .byte 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7 + + .align 4 +_B_lolo: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 + + .align 4 +_B_Vres0: + .byte 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31 + .align 4 +_B_Ures0: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31 + + .align 4 +_B_hihi: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23
diff --git a/vp8/common/ppc/platform_altivec.asm b/vp8/common/ppc/platform_altivec.asm new file mode 100644 index 0000000..227ef2a --- /dev/null +++ b/vp8/common/ppc/platform_altivec.asm
@@ -0,0 +1,58 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl save_platform_context + .globl restore_platform_context + +.macro W V P + stvx \V, 0, \P + addi \P, \P, 16 +.endm + +.macro R V P + lvx \V, 0, \P + addi \P, \P, 16 +.endm + +;# r3 context_ptr + .align 2 +save_platform_contex: + W v20, r3 + W v21, r3 + W v22, r3 + W v23, r3 + W v24, r3 + W v25, r3 + W v26, r3 + W v27, r3 + W v28, r3 + W v29, r3 + W v30, r3 + W v31, r3 + + blr + +;# r3 context_ptr + .align 2 +restore_platform_context: + R v20, r3 + R v21, r3 + R v22, r3 + R v23, r3 + R v24, r3 + R v25, r3 + R v26, r3 + R v27, r3 + R v28, r3 + R v29, r3 + R v30, r3 + R v31, r3 + + blr
diff --git a/vp8/common/ppc/recon_altivec.asm b/vp8/common/ppc/recon_altivec.asm new file mode 100644 index 0000000..f478b95 --- /dev/null +++ b/vp8/common/ppc/recon_altivec.asm
@@ -0,0 +1,174 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl recon4b_ppc + .globl recon2b_ppc + .globl recon_b_ppc + +.macro row_of16 Diff Pred Dst Stride + lvx v1, 0, \Pred ;# v1 = pred = p0..p15 + addi \Pred, \Pred, 16 ;# next pred + vmrghb v2, v0, v1 ;# v2 = 16-bit p0..p7 + lvx v3, 0, \Diff ;# v3 = d0..d7 + vaddshs v2, v2, v3 ;# v2 = r0..r7 + vmrglb v1, v0, v1 ;# v1 = 16-bit p8..p15 + lvx v3, r8, \Diff ;# v3 = d8..d15 + addi \Diff, \Diff, 32 ;# next diff + vaddshs v3, v3, v1 ;# v3 = r8..r15 + vpkshus v2, v2, v3 ;# v2 = 8-bit r0..r15 + stvx v2, 0, \Dst ;# to dst + add \Dst, \Dst, \Stride ;# next dst +.endm + + .text + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride +recon4b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + li r8, 16 + + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + row_of16 r3, r4, r5, r6 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr + +.macro two_rows_of8 Diff Pred Dst Stride write_first_four_pels + lvx v1, 0, \Pred ;# v1 = pred = p0..p15 + vmrghb v2, v0, v1 ;# v2 = 16-bit p0..p7 + lvx v3, 0, \Diff ;# v3 = d0..d7 + vaddshs v2, v2, v3 ;# v2 = r0..r7 + vmrglb v1, v0, v1 ;# v1 = 16-bit p8..p15 + lvx v3, r8, \Diff ;# v2 = d8..d15 + vaddshs v3, v3, v1 ;# v3 = r8..r15 + vpkshus v2, v2, v3 ;# v3 = 8-bit r0..r15 + stvx v2, 0, r10 ;# 2 rows to dst from buf + lwz r0, 0(r10) +.if \write_first_four_pels + stw r0, 0(\Dst) + .else + stwux r0, \Dst, \Stride +.endif + lwz r0, 4(r10) + stw r0, 4(\Dst) + lwz r0, 8(r10) + stwux r0, \Dst, \Stride ;# advance dst to next row + lwz r0, 12(r10) + stw r0, 4(\Dst) +.endm + + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride + +recon2b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + li r8, 16 + + la r10, -48(r1) ;# buf + + two_rows_of8 r3, r4, r5, r6, 1 + + addi r4, r4, 16; ;# next pred + addi r3, r3, 32; ;# next diff + + two_rows_of8 r3, r4, r5, r6, 0 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr + +.macro get_two_diff_rows + stw r0, 0(r10) + lwz r0, 4(r3) + stw r0, 4(r10) + lwzu r0, 32(r3) + stw r0, 8(r10) + lwz r0, 4(r3) + stw r0, 12(r10) + lvx v3, 0, r10 +.endm + + .align 2 +;# r3 = short *diff_ptr, +;# r4 = unsigned char *pred_ptr, +;# r5 = unsigned char *dst_ptr, +;# r6 = int stride +recon_b_ppc: + mfspr r0, 256 ;# get old VRSAVE + stw r0, -8(r1) ;# save old VRSAVE to stack + oris r0, r0, 0xf000 + mtspr 256,r0 ;# set VRSAVE + + vxor v0, v0, v0 + + la r10, -48(r1) ;# buf + + lwz r0, 0(r4) + stw r0, 0(r10) + lwz r0, 16(r4) + stw r0, 4(r10) + lwz r0, 32(r4) + stw r0, 8(r10) + lwz r0, 48(r4) + stw r0, 12(r10) + + lvx v1, 0, r10; ;# v1 = pred = p0..p15 + + lwz r0, 0(r3) ;# v3 = d0..d7 + + get_two_diff_rows + + vmrghb v2, v0, v1; ;# v2 = 16-bit p0..p7 + vaddshs v2, v2, v3; ;# v2 = r0..r7 + + lwzu r0, 32(r3) ;# v3 = d8..d15 + + get_two_diff_rows + + vmrglb v1, v0, v1; ;# v1 = 16-bit p8..p15 + vaddshs v3, v3, v1; ;# v3 = r8..r15 + + vpkshus v2, v2, v3; ;# v2 = 8-bit r0..r15 + stvx v2, 0, r10; ;# 16 pels to dst from buf + + lwz r0, 0(r10) + stw r0, 0(r5) + lwz r0, 4(r10) + stwux r0, r5, r6 + lwz r0, 8(r10) + stwux r0, r5, r6 + lwz r0, 12(r10) + stwx r0, r5, r6 + + lwz r12, -8(r1) ;# restore old VRSAVE from stack + mtspr 256, r12 ;# reset old VRSAVE + + blr
diff --git a/vp8/common/ppc/systemdependent.c b/vp8/common/ppc/systemdependent.c new file mode 100644 index 0000000..2847310 --- /dev/null +++ b/vp8/common/ppc/systemdependent.c
@@ -0,0 +1,170 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "g_common.h" +#include "subpixel.h" +#include "loopfilter.h" +#include "recon.h" +#include "idct.h" +#include "onyxc_int.h" + +void (*vp8_short_idct4x4)(short *input, short *output, int pitch); +void (*vp8_short_idct4x4_1)(short *input, short *output, int pitch); +void (*vp8_dc_only_idct)(short input_dc, short *output, int pitch); + +extern void (*vp8_post_proc_down_and_across)( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +); + +extern void (*vp8_mbpost_proc_down)(unsigned char *dst, int pitch, int rows, int cols, int flimit); +extern void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit); +extern void (*vp8_mbpost_proc_across_ip)(unsigned char *src, int pitch, int rows, int cols, int flimit); +extern void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit); + +extern void vp8_post_proc_down_and_across_c +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +); +void vp8_plane_add_noise_c(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a); + +extern copy_mem_block_function *vp8_copy_mem16x16; +extern copy_mem_block_function *vp8_copy_mem8x8; +extern copy_mem_block_function *vp8_copy_mem8x4; + +// PPC +extern subpixel_predict_function sixtap_predict_ppc; +extern subpixel_predict_function sixtap_predict8x4_ppc; +extern subpixel_predict_function sixtap_predict8x8_ppc; +extern subpixel_predict_function sixtap_predict16x16_ppc; +extern subpixel_predict_function bilinear_predict4x4_ppc; +extern subpixel_predict_function bilinear_predict8x4_ppc; +extern subpixel_predict_function bilinear_predict8x8_ppc; +extern subpixel_predict_function bilinear_predict16x16_ppc; + +extern copy_mem_block_function copy_mem16x16_ppc; + +void recon_b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void recon2b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void recon4b_ppc(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); + +extern void short_idct4x4llm_ppc(short *input, short *output, int pitch); + +// Generic C +extern subpixel_predict_function vp8_sixtap_predict_c; +extern subpixel_predict_function vp8_sixtap_predict8x4_c; +extern subpixel_predict_function vp8_sixtap_predict8x8_c; +extern subpixel_predict_function vp8_sixtap_predict16x16_c; +extern subpixel_predict_function vp8_bilinear_predict4x4_c; +extern subpixel_predict_function vp8_bilinear_predict8x4_c; +extern subpixel_predict_function vp8_bilinear_predict8x8_c; +extern subpixel_predict_function vp8_bilinear_predict16x16_c; + +extern copy_mem_block_function vp8_copy_mem16x16_c; +extern copy_mem_block_function vp8_copy_mem8x8_c; +extern copy_mem_block_function vp8_copy_mem8x4_c; + +void vp8_recon_b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void vp8_recon2b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); +void vp8_recon4b_c(short *diff_ptr, unsigned char *pred_ptr, unsigned char *dst_ptr, int stride); + +extern void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); +extern void vp8_short_idct4x4llm_c(short *input, short *output, int pitch); +extern void vp8_dc_only_idct_c(short input_dc, short *output, int pitch); + +// PPC +extern loop_filter_block_function loop_filter_mbv_ppc; +extern loop_filter_block_function loop_filter_bv_ppc; +extern loop_filter_block_function loop_filter_mbh_ppc; +extern loop_filter_block_function loop_filter_bh_ppc; + +extern loop_filter_block_function loop_filter_mbvs_ppc; +extern loop_filter_block_function loop_filter_bvs_ppc; +extern loop_filter_block_function loop_filter_mbhs_ppc; +extern loop_filter_block_function loop_filter_bhs_ppc; + +// Generic C +extern loop_filter_block_function vp8_loop_filter_mbv_c; +extern loop_filter_block_function vp8_loop_filter_bv_c; +extern loop_filter_block_function vp8_loop_filter_mbh_c; +extern loop_filter_block_function vp8_loop_filter_bh_c; + +extern loop_filter_block_function vp8_loop_filter_mbvs_c; +extern loop_filter_block_function vp8_loop_filter_bvs_c; +extern loop_filter_block_function vp8_loop_filter_mbhs_c; +extern loop_filter_block_function vp8_loop_filter_bhs_c; + +extern loop_filter_block_function *vp8_lf_mbvfull; +extern loop_filter_block_function *vp8_lf_mbhfull; +extern loop_filter_block_function *vp8_lf_bvfull; +extern loop_filter_block_function *vp8_lf_bhfull; + +extern loop_filter_block_function *vp8_lf_mbvsimple; +extern loop_filter_block_function *vp8_lf_mbhsimple; +extern loop_filter_block_function *vp8_lf_bvsimple; +extern loop_filter_block_function *vp8_lf_bhsimple; + +void vp8_clear_c(void) +{ +} + +void vp8_machine_specific_config(void) +{ + // Pure C: + vp8_clear_system_state = vp8_clear_c; + vp8_recon_b = vp8_recon_b_c; + vp8_recon4b = vp8_recon4b_c; + vp8_recon2b = vp8_recon2b_c; + + vp8_bilinear_predict16x16 = bilinear_predict16x16_ppc; + vp8_bilinear_predict8x8 = bilinear_predict8x8_ppc; + vp8_bilinear_predict8x4 = bilinear_predict8x4_ppc; + vp8_bilinear_predict = bilinear_predict4x4_ppc; + + vp8_sixtap_predict16x16 = sixtap_predict16x16_ppc; + vp8_sixtap_predict8x8 = sixtap_predict8x8_ppc; + vp8_sixtap_predict8x4 = sixtap_predict8x4_ppc; + vp8_sixtap_predict = sixtap_predict_ppc; + + vp8_short_idct4x4_1 = vp8_short_idct4x4llm_1_c; + vp8_short_idct4x4 = short_idct4x4llm_ppc; + vp8_dc_only_idct = vp8_dc_only_idct_c; + + vp8_lf_mbvfull = loop_filter_mbv_ppc; + vp8_lf_bvfull = loop_filter_bv_ppc; + vp8_lf_mbhfull = loop_filter_mbh_ppc; + vp8_lf_bhfull = loop_filter_bh_ppc; + + vp8_lf_mbvsimple = loop_filter_mbvs_ppc; + vp8_lf_bvsimple = loop_filter_bvs_ppc; + vp8_lf_mbhsimple = loop_filter_mbhs_ppc; + vp8_lf_bhsimple = loop_filter_bhs_ppc; + + vp8_post_proc_down_and_across = vp8_post_proc_down_and_across_c; + vp8_mbpost_proc_down = vp8_mbpost_proc_down_c; + vp8_mbpost_proc_across_ip = vp8_mbpost_proc_across_ip_c; + vp8_plane_add_noise = vp8_plane_add_noise_c; + + vp8_copy_mem16x16 = copy_mem16x16_ppc; + vp8_copy_mem8x8 = vp8_copy_mem8x8_c; + vp8_copy_mem8x4 = vp8_copy_mem8x4_c; + +}
diff --git a/vp8/common/ppflags.h b/vp8/common/ppflags.h new file mode 100644 index 0000000..c663976 --- /dev/null +++ b/vp8/common/ppflags.h
@@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_PPFLAGS_H +#define __INC_PPFLAGS_H +enum +{ + VP8D_NOFILTERING = 0, + VP8D_DEBLOCK = 1, + VP8D_DEMACROBLOCK = 2, + VP8D_ADDNOISE = 4, + VP8D_DEBUG_LEVEL1 = 8, + VP8D_DEBUG_LEVEL2 = 16, + VP8D_DEBUG_LEVEL3 = 32, + VP8D_DEBUG_LEVEL4 = 64, +}; + +#endif
diff --git a/vp8/common/pragmas.h b/vp8/common/pragmas.h new file mode 100644 index 0000000..25a4b77 --- /dev/null +++ b/vp8/common/pragmas.h
@@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + + + +#ifdef __INTEL_COMPILER +#pragma warning(disable:997 1011 170) +#endif +#ifdef _MSC_VER +#pragma warning(disable:4799) +#endif
diff --git a/vp8/common/predictdc.c b/vp8/common/predictdc.c new file mode 100644 index 0000000..df4c96e --- /dev/null +++ b/vp8/common/predictdc.c
@@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> +#include "blockd.h" + + +void vp8_predict_dc(short *lastdc, short *thisdc, short quant, short *cons) +{ + int diff; + int sign; + int last_dc = *lastdc; + int this_dc = *thisdc; + + if (*cons > DCPREDCNTTHRESH) + { + this_dc += last_dc; + } + + diff = abs(last_dc - this_dc); + sign = (last_dc >> 31) ^(this_dc >> 31); + sign |= (!last_dc | !this_dc); + + if (sign) + { + *cons = 0; + } + else + { + if (diff <= DCPREDSIMTHRESH * quant) + (*cons)++ ; + } + + *thisdc = this_dc; + *lastdc = this_dc; +}
diff --git a/vp8/common/predictdc.h b/vp8/common/predictdc.h new file mode 100644 index 0000000..b8871e4 --- /dev/null +++ b/vp8/common/predictdc.h
@@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __PREDICTDC_H +#define __PREDICTDC_H + +void uvvp8_predict_dc(short *lastdc, short *thisdc, short quant, short *cons); +void vp8_predict_dc(short *lastdc, short *thisdc, short quant, short *cons); + +#endif
diff --git a/vp8/common/preproc.h b/vp8/common/preproc.h new file mode 100644 index 0000000..00ec9a8 --- /dev/null +++ b/vp8/common/preproc.h
@@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : preproc.h +* +* Description : simple preprocessor +* +****************************************************************************/ + +#ifndef __INC_PREPROC_H +#define __INC_PREPROC_H + +/**************************************************************************** +* Types +****************************************************************************/ + +typedef struct +{ + unsigned char *frame_buffer; + int frame; + unsigned int *fixed_divide; + + unsigned char *frame_buffer_alloc; + unsigned int *fixed_divide_alloc; +} pre_proc_instance; + +/**************************************************************************** +* Functions. +****************************************************************************/ +void pre_proc_machine_specific_config(void); +void delete_pre_proc(pre_proc_instance *ppi); +int init_pre_proc(pre_proc_instance *ppi, int frame_size); +extern void spatial_filter_c(pre_proc_instance *ppi, unsigned char *s, unsigned char *d, int width, int height, int pitch, int strength); +extern void (*temp_filter)(pre_proc_instance *ppi, unsigned char *s, unsigned char *d, int bytes, int strength); + +#endif
diff --git a/vp8/common/preprocif.h b/vp8/common/preprocif.h new file mode 100644 index 0000000..986c45b --- /dev/null +++ b/vp8/common/preprocif.h
@@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : preproc_if.h +* +* Description : Pre-processor interface header file. +* +****************************************************************************/ + +#ifndef __PREPROC_IF_H +#define __PREPROC_IF_H + +/**************************************************************************** +* Header Files +****************************************************************************/ +#include "type_aliases.h" + +/**************************************************************************** +* Types +****************************************************************************/ + +typedef struct +{ + UINT8 *Yuv0ptr; + UINT8 *Yuv1ptr; + + UINT8 *frag_info; // blocks coded : passed in + UINT32 frag_info_element_size; // size of each element + UINT32 frag_info_coded_mask; // mask to get at whether fragment is coded + + UINT32 *region_index; // Gives pixel index for top left of each block + UINT32 video_frame_height; + UINT32 video_frame_width; + UINT8 hfrag_pixels; + UINT8 vfrag_pixels; + +} SCAN_CONFIG_DATA; + +typedef enum +{ + SCP_FILTER_ON_OFF, + SCP_SET_SRF_OFFSET, + SCP_SET_EBO_ON_OFF, + SCP_SET_VCAP_LEVEL_OFFSET, + SCP_SET_SHOW_LOCAL + +} SCP_SETTINGS; + +typedef struct PP_INSTANCE *x_pp_inst; + +/**************************************************************************** +* Module statics +****************************************************************************/ +/* Controls whether Early break out is on or off in default case */ +#define EARLY_BREAKOUT_DEFAULT TRUE + +/**************************************************************************** +* Functions +****************************************************************************/ +extern void set_scan_param(x_pp_inst ppi, UINT32 param_id, INT32 param_value); +extern UINT32 yuvanalyse_frame(x_pp_inst ppi, UINT32 *KFIndicator); +extern x_pp_inst create_pp_instance(void); +extern void delete_pp_instance(x_pp_inst *); +extern BOOL scan_yuvinit(x_pp_inst, SCAN_CONFIG_DATA *scan_config_ptr); + +#endif
diff --git a/vp8/common/proposed.h b/vp8/common/proposed.h new file mode 100644 index 0000000..1171ede --- /dev/null +++ b/vp8/common/proposed.h
@@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +typedef struct core_codec *codec_ptr; +typedef struct interface_table *interface_ptr; + +typedef struct +{ + void (*Initialize)(); + void (*Shutdown)(); + codec_ptr(*Create)(); + int (*compress_frame)(codec_ptr, unsigned int *frame_flags, YV12_BUFFER_CONFIG *sd, unsigned long *size, char *dest, INT64 time_stamp); + int (*show_frame)(codec_ptr , YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags); + void (*Remove)(codec_ptr *comp); + interface_ptr(*get_interface)(unsigned int id); + +} core_codec; + +typedef struct +{ + int (*set_bitrate)(codec_ptr, END_USAGE usage, int Datarate); + int (*get_bitrate)(codec_ptr, END_USAGE *usage, int *Datarate); + int (*set_mode)(codec_ptr, MODE mode, int Speed, char *File); + int (*get_mode)(codec_ptr, MODE *mode, int *Speed, char **File); +} codec_settings_basic; + +typedef struct +{ + int (*set_bitrate)(codec_ptr, END_USAGE usage, int Datarate); + int (*get_bitrate)(codec_ptr, END_USAGE *usage, int *Datarate); + int (*set_mode)(codec_ptr, MODE mode, int Speed, char *File); + int (*get_mode)(codec_ptr, MODE *mode, int *Speed, char **File); + int (*set_denoise)(codec_ptr, int Level); + int (*get_denoise)(codec_ptr, int *Level); + int (*set_sharpness)(codec_ptr, int sharpness); + int (*get_sharpness)(codec_ptr, int *sharpness); + int (*set_keyframing)(codec_ptr, int Auto, int max_distance); + int (*get_keyframing)(codec_ptr, int *Auto, int *max_distance); + int (*set_buffering)(codec_ptr, int buffer_level, int max_buffer_level); + int (*get_buffering)(codec_ptr, int *buffer_level, int *max_buffer_level); + int (*set_adjust_frame_rate)(codec_ptr, int Allowed, int at_buffer_level_pct); + int (*get_adjust_frame_rate)(codec_ptr, int *Allowed, int *at_buffer_level_pct); + int (*set_adjust_frame_size)(codec_ptr, int Allowed, int down_at_buffer_level_pct, int up_at_buffer_level_pct); + int (*get_adjust_frame_size)(codec_ptr, int *Allowed, int *down_at_buffer_level_pct, int *up_at_buffer_level_pct); + int (*set_adjust_quality)(codec_ptr, int Allowed, int min_quantizer, int max_quantizer); + int (*get_adjust_quality)(codec_ptr, int *Allowed, int *min_quantizer, int *max_quantizer); + int (*set_vbrparms)(codec_ptr, int Bias, int Min, int Max); + int (*get_vbrparms)(codec_ptr, int *Bias, int *Min, int *Max); + +} codec_settings_v1; + +typedef struct +{ + int (*request_recovery)(codec_ptr); + int (*request_droppable)(codec_ptr); + int (*internal_size)(codec_ptr, VPX_SCALING Vertical, VPX_SCALING Horizontal); + int (*update_last)(codec_ptr); + int (*update_gold)(codec_ptr); + int (*use_only_last)(codec_ptr); + int (*use_only_gold)(codec_ptr); + int (*update_entropy)(codec_ptr); + +} codec_realtime_requests;
diff --git a/vp8/common/quant_common.c b/vp8/common/quant_common.c new file mode 100644 index 0000000..09fe31f --- /dev/null +++ b/vp8/common/quant_common.c
@@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "quant_common.h" + +static const int dc_qlookup[QINDEX_RANGE] = +{ + 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 143, 145, 148, 151, 154, 157, +}; + +static const int ac_qlookup[QINDEX_RANGE] = +{ + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, 249, 254, 259, 264, 269, 274, 279, 284, +}; + + +int vp8_dc_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ]; + return retval; +} + +int vp8_dc2quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ] * 2; + return retval; + +} +int vp8_dc_uv_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = dc_qlookup[ QIndex ]; + + if (retval > 132) + retval = 132; + + return retval; +} + +int vp8_ac_yquant(int QIndex) +{ + int retval; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = ac_qlookup[ QIndex ]; + return retval; +} + +int vp8_ac2quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = (ac_qlookup[ QIndex ] * 155) / 100; + + if (retval < 8) + retval = 8; + + return retval; +} +int vp8_ac_uv_quant(int QIndex, int Delta) +{ + int retval; + + QIndex = QIndex + Delta; + + if (QIndex > 127) + QIndex = 127; + else if (QIndex < 0) + QIndex = 0; + + retval = ac_qlookup[ QIndex ]; + return retval; +}
diff --git a/vp8/common/quant_common.h b/vp8/common/quant_common.h new file mode 100644 index 0000000..0c92ce8 --- /dev/null +++ b/vp8/common/quant_common.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "string.h" +#include "blockd.h" +#include "onyxc_int.h" + +extern int vp8_ac_yquant(int QIndex); +extern int vp8_dc_quant(int QIndex, int Delta); +extern int vp8_dc2quant(int QIndex, int Delta); +extern int vp8_ac2quant(int QIndex, int Delta); +extern int vp8_dc_uv_quant(int QIndex, int Delta); +extern int vp8_ac_uv_quant(int QIndex, int Delta);
diff --git a/vp8/common/recon.c b/vp8/common/recon.c new file mode 100644 index 0000000..d1268ea --- /dev/null +++ b/vp8/common/recon.c
@@ -0,0 +1,137 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "blockd.h" + +void vp8_recon_b_c +( + unsigned char *pred_ptr, + short *diff_ptr, + unsigned char *dst_ptr, + int stride +) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + diff_ptr += 16; + pred_ptr += 16; + } +} + +void vp8_recon4b_c +( + unsigned char *pred_ptr, + short *diff_ptr, + unsigned char *dst_ptr, + int stride +) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 16; c++) + { + int a = diff_ptr[c] + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + diff_ptr += 16; + pred_ptr += 16; + } +} + +void vp8_recon2b_c +( + unsigned char *pred_ptr, + short *diff_ptr, + unsigned char *dst_ptr, + int stride +) +{ + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 8; c++) + { + int a = diff_ptr[c] + pred_ptr[c] ; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + diff_ptr += 8; + pred_ptr += 8; + } +} + +void vp8_recon16x16mby(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + for (i = 0; i < 16; i += 4) + { + BLOCKD *b = &x->block[i]; + + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } +} + +void vp8_recon16x16mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + for (i = 0; i < 16; i += 4) + { + BLOCKD *b = &x->block[i]; + + RECON_INVOKE(rtcd, recon4)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } + + for (i = 16; i < 24; i += 2) + { + BLOCKD *b = &x->block[i]; + + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } +}
diff --git a/vp8/common/recon.h b/vp8/common/recon.h new file mode 100644 index 0000000..f65a90f --- /dev/null +++ b/vp8/common/recon.h
@@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_RECON_H +#define __INC_RECON_H + +#define prototype_copy_block(sym) \ + void sym(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch) + +#define prototype_recon_block(sym) \ + void sym(unsigned char *pred, short *diff, unsigned char *dst, int pitch); + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/recon_x86.h" +#endif + +#if ARCH_ARM +#include "arm/recon_arm.h" +#endif + +#ifndef vp8_recon_copy16x16 +#define vp8_recon_copy16x16 vp8_copy_mem16x16_c +#endif +extern prototype_copy_block(vp8_recon_copy16x16); + +#ifndef vp8_recon_copy8x8 +#define vp8_recon_copy8x8 vp8_copy_mem8x8_c +#endif +extern prototype_copy_block(vp8_recon_copy8x8); + +#ifndef vp8_recon_copy8x4 +#define vp8_recon_copy8x4 vp8_copy_mem8x4_c +#endif +extern prototype_copy_block(vp8_recon_copy8x4); + +#ifndef vp8_recon_recon +#define vp8_recon_recon vp8_recon_b_c +#endif +extern prototype_recon_block(vp8_recon_recon); + +#ifndef vp8_recon_recon2 +#define vp8_recon_recon2 vp8_recon2b_c +#endif +extern prototype_recon_block(vp8_recon_recon2); + +#ifndef vp8_recon_recon4 +#define vp8_recon_recon4 vp8_recon4b_c +#endif +extern prototype_recon_block(vp8_recon_recon4); + +typedef prototype_copy_block((*vp8_copy_block_fn_t)); +typedef prototype_recon_block((*vp8_recon_fn_t)); +typedef struct +{ + vp8_copy_block_fn_t copy16x16; + vp8_copy_block_fn_t copy8x8; + vp8_copy_block_fn_t copy8x4; + vp8_recon_fn_t recon; + vp8_recon_fn_t recon2; + vp8_recon_fn_t recon4; +} vp8_recon_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define RECON_INVOKE(ctx,fn) (ctx)->fn +#else +#define RECON_INVOKE(ctx,fn) vp8_recon_##fn +#endif + +#include "blockd.h" +void vp8_recon16x16mby(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +void vp8_recon16x16mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +void vp8_recon_intra4x4mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +void vp8_recon_intra_mbuv(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x); +#endif
diff --git a/vp8/common/reconinter.c b/vp8/common/reconinter.c new file mode 100644 index 0000000..c48886d --- /dev/null +++ b/vp8/common/reconinter.c
@@ -0,0 +1,680 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "subpixel.h" +#include "blockd.h" +#include "reconinter.h" +#if CONFIG_RUNTIME_CPU_DETECT +#include "onyxc_int.h" +#endif + +// use this define on systems where unaligned int reads and writes are +// not allowed, i.e. ARM architectures +//#define MUST_BE_ALIGNED + + +static const int bbb[4] = {0, 2, 8, 10}; + + + +void vp8_copy_mem16x16_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + + int r; + + for (r = 0; r < 16; r++) + { +#ifdef MUST_BE_ALIGNED + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + dst[8] = src[8]; + dst[9] = src[9]; + dst[10] = src[10]; + dst[11] = src[11]; + dst[12] = src[12]; + dst[13] = src[13]; + dst[14] = src[14]; + dst[15] = src[15]; + +#else + ((int *)dst)[0] = ((int *)src)[0] ; + ((int *)dst)[1] = ((int *)src)[1] ; + ((int *)dst)[2] = ((int *)src)[2] ; + ((int *)dst)[3] = ((int *)src)[3] ; + +#endif + src += src_stride; + dst += dst_stride; + + } + +} + +void vp8_copy_mem8x8_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 8; r++) + { +#ifdef MUST_BE_ALIGNED + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +#else + ((int *)dst)[0] = ((int *)src)[0] ; + ((int *)dst)[1] = ((int *)src)[1] ; +#endif + src += src_stride; + dst += dst_stride; + + } + +} + +void vp8_copy_mem8x4_c( + unsigned char *src, + int src_stride, + unsigned char *dst, + int dst_stride) +{ + int r; + + for (r = 0; r < 4; r++) + { +#ifdef MUST_BE_ALIGNED + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +#else + ((int *)dst)[0] = ((int *)src)[0] ; + ((int *)dst)[1] = ((int *)src)[1] ; +#endif + src += src_stride; + dst += dst_stride; + + } + +} + + + +void vp8_build_inter_predictors_b(BLOCKD *d, int pitch, vp8_subpix_fn_t sppf) +{ + int r; + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d->predictor; + + ptr_base = *(d->base_pre); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + sppf(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); + } + else + { + ptr_base += d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + ptr = ptr_base; + + for (r = 0; r < 4; r++) + { +#ifdef MUST_BE_ALIGNED + pred_ptr[0] = ptr[0]; + pred_ptr[1] = ptr[1]; + pred_ptr[2] = ptr[2]; + pred_ptr[3] = ptr[3]; +#else + *(int *)pred_ptr = *(int *)ptr ; +#endif + pred_ptr += pitch; + ptr += d->pre_stride; + } + } +} + +void vp8_build_inter_predictors4b(MACROBLOCKD *x, BLOCKD *d, int pitch) +{ + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d->predictor; + + ptr_base = *(d->base_pre); + ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x8(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x8)(ptr, d->pre_stride, pred_ptr, pitch); + } +} + +void vp8_build_inter_predictors2b(MACROBLOCKD *x, BLOCKD *d, int pitch) +{ + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d->predictor; + + ptr_base = *(d->base_pre); + ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x4(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, pred_ptr, pitch); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x4)(ptr, d->pre_stride, pred_ptr, pitch); + } +} + + +void vp8_build_inter_predictors_mbuv(MACROBLOCKD *x) +{ + int i; + + if (x->mbmi.ref_frame != INTRA_FRAME && x->mbmi.mode != SPLITMV) + { + unsigned char *uptr, *vptr; + unsigned char *upred_ptr = &x->predictor[256]; + unsigned char *vpred_ptr = &x->predictor[320]; + + int mv_row = x->block[16].bmi.mv.as_mv.row; + int mv_col = x->block[16].bmi.mv.as_mv.col; + int offset; + int pre_stride = x->block[16].pre_stride; + + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->pre.u_buffer + offset; + vptr = x->pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8); + x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, upred_ptr, 8); + RECON_INVOKE(&x->rtcd->recon, copy8x8)(vptr, pre_stride, vpred_ptr, 8); + } + } + else + { + for (i = 16; i < 24; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + vp8_build_inter_predictors2b(x, d0, 8); + else + { + vp8_build_inter_predictors_b(d0, 8, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 8, x->subpixel_predict); + } + } + } +} + + +void vp8_build_inter_predictors_mby(MACROBLOCKD *x) +{ + if (x->mbmi.ref_frame != INTRA_FRAME && x->mbmi.mode != SPLITMV) + { + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = x->predictor; + int mv_row = x->mbmi.mv.as_mv.row; + int mv_col = x->mbmi.mv.as_mv.col; + int pre_stride = x->block[0].pre_stride; + + ptr_base = x->pre.y_buffer; + ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, pred_ptr, 16); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, pred_ptr, 16); + } + } + else + { + int i; + + if (x->mbmi.partitioning < 3) + { + for (i = 0; i < 4; i++) + { + BLOCKD *d = &x->block[bbb[i]]; + vp8_build_inter_predictors4b(x, d, 16); + } + + } + else + { + for (i = 0; i < 16; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + vp8_build_inter_predictors2b(x, d0, 16); + else + { + vp8_build_inter_predictors_b(d0, 16, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 16, x->subpixel_predict); + } + + } + } + } +} + +void vp8_build_inter_predictors_mb(MACROBLOCKD *x) +{ + if (x->mbmi.ref_frame != INTRA_FRAME && x->mbmi.mode != SPLITMV) + { + int offset; + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *uptr, *vptr; + unsigned char *pred_ptr = x->predictor; + unsigned char *upred_ptr = &x->predictor[256]; + unsigned char *vpred_ptr = &x->predictor[320]; + + int mv_row = x->mbmi.mv.as_mv.row; + int mv_col = x->mbmi.mv.as_mv.col; + int pre_stride = x->block[0].pre_stride; + + ptr_base = x->pre.y_buffer; + ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, pred_ptr, 16); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, pred_ptr, 16); + } + + mv_row = x->block[16].bmi.mv.as_mv.row; + mv_col = x->block[16].bmi.mv.as_mv.col; + pre_stride >>= 1; + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->pre.u_buffer + offset; + vptr = x->pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, 8); + x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, 8); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, upred_ptr, 8); + RECON_INVOKE(&x->rtcd->recon, copy8x8)(vptr, pre_stride, vpred_ptr, 8); + } + } + else + { + int i; + + if (x->mbmi.partitioning < 3) + { + for (i = 0; i < 4; i++) + { + BLOCKD *d = &x->block[bbb[i]]; + vp8_build_inter_predictors4b(x, d, 16); + } + } + else + { + for (i = 0; i < 16; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + vp8_build_inter_predictors2b(x, d0, 16); + else + { + vp8_build_inter_predictors_b(d0, 16, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 16, x->subpixel_predict); + } + + } + + } + + for (i = 16; i < 24; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + vp8_build_inter_predictors2b(x, d0, 8); + else + { + vp8_build_inter_predictors_b(d0, 8, x->subpixel_predict); + vp8_build_inter_predictors_b(d1, 8, x->subpixel_predict); + } + + } + + } +} + +void vp8_build_uvmvs(MACROBLOCKD *x, int fullpixel) +{ + int i, j; + + if (x->mbmi.mode == SPLITMV) + { + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + int yoffset = i * 8 + j * 2; + int uoffset = 16 + i * 2 + j; + int voffset = 20 + i * 2 + j; + + int temp; + + temp = x->block[yoffset ].bmi.mv.as_mv.row + + x->block[yoffset+1].bmi.mv.as_mv.row + + x->block[yoffset+4].bmi.mv.as_mv.row + + x->block[yoffset+5].bmi.mv.as_mv.row; + + if (temp < 0) temp -= 4; + else temp += 4; + + x->block[uoffset].bmi.mv.as_mv.row = temp / 8; + + if (fullpixel) + x->block[uoffset].bmi.mv.as_mv.row = (temp / 8) & 0xfffffff8; + + temp = x->block[yoffset ].bmi.mv.as_mv.col + + x->block[yoffset+1].bmi.mv.as_mv.col + + x->block[yoffset+4].bmi.mv.as_mv.col + + x->block[yoffset+5].bmi.mv.as_mv.col; + + if (temp < 0) temp -= 4; + else temp += 4; + + x->block[uoffset].bmi.mv.as_mv.col = temp / 8; + + if (fullpixel) + x->block[uoffset].bmi.mv.as_mv.col = (temp / 8) & 0xfffffff8; + + x->block[voffset].bmi.mv.as_mv.row = x->block[uoffset].bmi.mv.as_mv.row ; + x->block[voffset].bmi.mv.as_mv.col = x->block[uoffset].bmi.mv.as_mv.col ; + } + } + } + else + { + int mvrow = x->mbmi.mv.as_mv.row; + int mvcol = x->mbmi.mv.as_mv.col; + + if (mvrow < 0) + mvrow -= 1; + else + mvrow += 1; + + if (mvcol < 0) + mvcol -= 1; + else + mvcol += 1; + + mvrow /= 2; + mvcol /= 2; + + for (i = 0; i < 8; i++) + { + x->block[ 16 + i].bmi.mv.as_mv.row = mvrow; + x->block[ 16 + i].bmi.mv.as_mv.col = mvcol; + + if (fullpixel) + { + x->block[ 16 + i].bmi.mv.as_mv.row = mvrow & 0xfffffff8; + x->block[ 16 + i].bmi.mv.as_mv.col = mvcol & 0xfffffff8; + } + } + } +} + + +// The following functions are wriiten for skip_recon_mb() to call. Since there is no recon in this +// situation, we can write the result directly to dst buffer instead of writing it to predictor +// buffer and then copying it to dst buffer. +static void vp8_build_inter_predictors_b_s(BLOCKD *d, unsigned char *dst_ptr, vp8_subpix_fn_t sppf) +{ + int r; + unsigned char *ptr_base; + unsigned char *ptr; + //unsigned char *pred_ptr = d->predictor; + int dst_stride = d->dst_stride; + int pre_stride = d->pre_stride; + + ptr_base = *(d->base_pre); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + sppf(ptr, pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, dst_ptr, dst_stride); + } + else + { + ptr_base += d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + ptr = ptr_base; + + for (r = 0; r < 4; r++) + { +#ifdef MUST_BE_ALIGNED + dst_ptr[0] = ptr[0]; + dst_ptr[1] = ptr[1]; + dst_ptr[2] = ptr[2]; + dst_ptr[3] = ptr[3]; +#else + *(int *)dst_ptr = *(int *)ptr ; +#endif + dst_ptr += dst_stride; + ptr += pre_stride; + } + } +} + + + +void vp8_build_inter_predictors_mb_s(MACROBLOCKD *x) +{ + //unsigned char *pred_ptr = x->block[0].predictor; + //unsigned char *dst_ptr = *(x->block[0].base_dst) + x->block[0].dst; + unsigned char *pred_ptr = x->predictor; + unsigned char *dst_ptr = x->dst.y_buffer; + + if (x->mbmi.mode != SPLITMV) + { + int offset; + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *uptr, *vptr; + //unsigned char *pred_ptr = x->predictor; + //unsigned char *upred_ptr = &x->predictor[256]; + //unsigned char *vpred_ptr = &x->predictor[320]; + unsigned char *udst_ptr = x->dst.u_buffer; + unsigned char *vdst_ptr = x->dst.v_buffer; + + int mv_row = x->mbmi.mv.as_mv.row; + int mv_col = x->mbmi.mv.as_mv.col; + int pre_stride = x->dst.y_stride; //x->block[0].pre_stride; + + ptr_base = x->pre.y_buffer; + ptr = ptr_base + (mv_row >> 3) * pre_stride + (mv_col >> 3); + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict16x16(ptr, pre_stride, mv_col & 7, mv_row & 7, dst_ptr, x->dst.y_stride); //x->block[0].dst_stride); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy16x16)(ptr, pre_stride, dst_ptr, x->dst.y_stride); //x->block[0].dst_stride); + } + + mv_row = x->block[16].bmi.mv.as_mv.row; + mv_col = x->block[16].bmi.mv.as_mv.col; + pre_stride >>= 1; + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->pre.u_buffer + offset; + vptr = x->pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + x->subpixel_predict8x8(uptr, pre_stride, mv_col & 7, mv_row & 7, udst_ptr, x->dst.uv_stride); + x->subpixel_predict8x8(vptr, pre_stride, mv_col & 7, mv_row & 7, vdst_ptr, x->dst.uv_stride); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x8)(uptr, pre_stride, udst_ptr, x->dst.uv_stride); + RECON_INVOKE(&x->rtcd->recon, copy8x8)(vptr, pre_stride, vdst_ptr, x->dst.uv_stride); + } + } + else + { + //note: this whole ELSE part is not executed at all. So, no way to test the correctness of my modification. Later, + //if sth is wrong, go back to what it is in build_inter_predictors_mb. + int i; + + if (x->mbmi.partitioning < 3) + { + for (i = 0; i < 4; i++) + { + BLOCKD *d = &x->block[bbb[i]]; + //vp8_build_inter_predictors4b(x, d, 16); + + { + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d->predictor; + + ptr_base = *(d->base_pre); + ptr = ptr_base + d->pre + (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (d->bmi.mv.as_mv.row & 7 || d->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x8(ptr, d->pre_stride, d->bmi.mv.as_mv.col & 7, d->bmi.mv.as_mv.row & 7, dst_ptr, x->dst.y_stride); //x->block[0].dst_stride); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x8)(ptr, d->pre_stride, dst_ptr, x->dst.y_stride); //x->block[0].dst_stride); + } + } + } + } + else + { + for (i = 0; i < 16; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + { + //vp8_build_inter_predictors2b(x, d0, 16); + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d0->predictor; + + ptr_base = *(d0->base_pre); + ptr = ptr_base + d0->pre + (d0->bmi.mv.as_mv.row >> 3) * d0->pre_stride + (d0->bmi.mv.as_mv.col >> 3); + + if (d0->bmi.mv.as_mv.row & 7 || d0->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x4(ptr, d0->pre_stride, d0->bmi.mv.as_mv.col & 7, d0->bmi.mv.as_mv.row & 7, dst_ptr, x->dst.y_stride); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x4)(ptr, d0->pre_stride, dst_ptr, x->dst.y_stride); + } + } + else + { + vp8_build_inter_predictors_b_s(d0, dst_ptr, x->subpixel_predict); + vp8_build_inter_predictors_b_s(d1, dst_ptr, x->subpixel_predict); + } + } + } + + for (i = 16; i < 24; i += 2) + { + BLOCKD *d0 = &x->block[i]; + BLOCKD *d1 = &x->block[i+1]; + + if (d0->bmi.mv.as_int == d1->bmi.mv.as_int) + { + //vp8_build_inter_predictors2b(x, d0, 8); + unsigned char *ptr_base; + unsigned char *ptr; + unsigned char *pred_ptr = d0->predictor; + + ptr_base = *(d0->base_pre); + ptr = ptr_base + d0->pre + (d0->bmi.mv.as_mv.row >> 3) * d0->pre_stride + (d0->bmi.mv.as_mv.col >> 3); + + if (d0->bmi.mv.as_mv.row & 7 || d0->bmi.mv.as_mv.col & 7) + { + x->subpixel_predict8x4(ptr, d0->pre_stride, d0->bmi.mv.as_mv.col & 7, d0->bmi.mv.as_mv.row & 7, dst_ptr, x->dst.y_stride); + } + else + { + RECON_INVOKE(&x->rtcd->recon, copy8x4)(ptr, d0->pre_stride, dst_ptr, x->dst.y_stride); + } + } + else + { + vp8_build_inter_predictors_b_s(d0, dst_ptr, x->subpixel_predict); + vp8_build_inter_predictors_b_s(d1, dst_ptr, x->subpixel_predict); + } + } + } +}
diff --git a/vp8/common/reconinter.h b/vp8/common/reconinter.h new file mode 100644 index 0000000..b2d1ae9 --- /dev/null +++ b/vp8/common/reconinter.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_RECONINTER_H +#define __INC_RECONINTER_H + +extern void vp8_build_inter_predictors_mb(MACROBLOCKD *x); +extern void vp8_build_inter_predictors_mb_s(MACROBLOCKD *x); + +extern void vp8_build_inter_predictors_mby(MACROBLOCKD *x); +extern void vp8_build_uvmvs(MACROBLOCKD *x, int fullpixel); +extern void vp8_build_inter_predictors_b(BLOCKD *d, int pitch, vp8_subpix_fn_t sppf); +extern void vp8_build_inter_predictors_mbuv(MACROBLOCKD *x); + +#endif
diff --git a/vp8/common/reconintra.c b/vp8/common/reconintra.c new file mode 100644 index 0000000..e33bce3 --- /dev/null +++ b/vp8/common/reconintra.c
@@ -0,0 +1,555 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "reconintra.h" +#include "vpx_mem/vpx_mem.h" + +// For skip_recon_mb(), add vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) and +// vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x). + +void vp8_recon_intra_mbuv(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + for (i = 16; i < 24; i += 2) + { + BLOCKD *b = &x->block[i]; + RECON_INVOKE(rtcd, recon2)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } +} + +void vp8_build_intra_predictors_mby(MACROBLOCKD *x) +{ + + unsigned char *yabove_row = x->dst.y_buffer - x->dst.y_stride; + unsigned char yleft_col[16]; + unsigned char ytop_left = yabove_row[-1]; + unsigned char *ypred_ptr = x->predictor; + int r, c, i; + + for (i = 0; i < 16; i++) + { + yleft_col[i] = x->dst.y_buffer [i* x->dst.y_stride -1]; + } + + // for Y + switch (x->mbmi.mode) + { + case DC_PRED: + { + int expected_dc; + int i; + int shift; + int average = 0; + + + if (x->up_available || x->left_available) + { + if (x->up_available) + { + for (i = 0; i < 16; i++) + { + average += yabove_row[i]; + } + } + + if (x->left_available) + { + + for (i = 0; i < 16; i++) + { + average += yleft_col[i]; + } + + } + + + + shift = 3 + x->up_available + x->left_available; + expected_dc = (average + (1 << (shift - 1))) >> shift; + } + else + { + expected_dc = 128; + } + + vpx_memset(ypred_ptr, expected_dc, 256); + } + break; + case V_PRED: + { + + for (r = 0; r < 16; r++) + { + + ((int *)ypred_ptr)[0] = ((int *)yabove_row)[0]; + ((int *)ypred_ptr)[1] = ((int *)yabove_row)[1]; + ((int *)ypred_ptr)[2] = ((int *)yabove_row)[2]; + ((int *)ypred_ptr)[3] = ((int *)yabove_row)[3]; + ypred_ptr += 16; + } + } + break; + case H_PRED: + { + + for (r = 0; r < 16; r++) + { + + vpx_memset(ypred_ptr, yleft_col[r], 16); + ypred_ptr += 16; + } + + } + break; + case TM_PRED: + { + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + int pred = yleft_col[r] + yabove_row[ c] - ytop_left; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + ypred_ptr[c] = pred; + } + + ypred_ptr += 16; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +} + +void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x) +{ + + unsigned char *yabove_row = x->dst.y_buffer - x->dst.y_stride; + unsigned char yleft_col[16]; + unsigned char ytop_left = yabove_row[-1]; + unsigned char *ypred_ptr = x->predictor; + int r, c, i; + + int y_stride = x->dst.y_stride; + ypred_ptr = x->dst.y_buffer; //x->predictor; + + for (i = 0; i < 16; i++) + { + yleft_col[i] = x->dst.y_buffer [i* x->dst.y_stride -1]; + } + + // for Y + switch (x->mbmi.mode) + { + case DC_PRED: + { + int expected_dc; + int i; + int shift; + int average = 0; + + + if (x->up_available || x->left_available) + { + if (x->up_available) + { + for (i = 0; i < 16; i++) + { + average += yabove_row[i]; + } + } + + if (x->left_available) + { + + for (i = 0; i < 16; i++) + { + average += yleft_col[i]; + } + + } + + + + shift = 3 + x->up_available + x->left_available; + expected_dc = (average + (1 << (shift - 1))) >> shift; + } + else + { + expected_dc = 128; + } + + //vpx_memset(ypred_ptr, expected_dc, 256); + for (r = 0; r < 16; r++) + { + vpx_memset(ypred_ptr, expected_dc, 16); + ypred_ptr += y_stride; //16; + } + } + break; + case V_PRED: + { + + for (r = 0; r < 16; r++) + { + + ((int *)ypred_ptr)[0] = ((int *)yabove_row)[0]; + ((int *)ypred_ptr)[1] = ((int *)yabove_row)[1]; + ((int *)ypred_ptr)[2] = ((int *)yabove_row)[2]; + ((int *)ypred_ptr)[3] = ((int *)yabove_row)[3]; + ypred_ptr += y_stride; //16; + } + } + break; + case H_PRED: + { + + for (r = 0; r < 16; r++) + { + + vpx_memset(ypred_ptr, yleft_col[r], 16); + ypred_ptr += y_stride; //16; + } + + } + break; + case TM_PRED: + { + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + int pred = yleft_col[r] + yabove_row[ c] - ytop_left; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + ypred_ptr[c] = pred; + } + + ypred_ptr += y_stride; //16; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +} + +void vp8_build_intra_predictors_mbuv(MACROBLOCKD *x) +{ + unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; + unsigned char uleft_col[16]; + unsigned char utop_left = uabove_row[-1]; + unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; + unsigned char vleft_col[20]; + unsigned char vtop_left = vabove_row[-1]; + unsigned char *upred_ptr = &x->predictor[256]; + unsigned char *vpred_ptr = &x->predictor[320]; + int i, j; + + for (i = 0; i < 8; i++) + { + uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; + vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; + } + + switch (x->mbmi.uv_mode) + { + case DC_PRED: + { + int expected_udc; + int expected_vdc; + int i; + int shift; + int Uaverage = 0; + int Vaverage = 0; + + if (x->up_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uabove_row[i]; + Vaverage += vabove_row[i]; + } + } + + if (x->left_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uleft_col[i]; + Vaverage += vleft_col[i]; + } + } + + if (!x->up_available && !x->left_available) + { + expected_udc = 128; + expected_vdc = 128; + } + else + { + shift = 2 + x->up_available + x->left_available; + expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; + expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; + } + + + vpx_memset(upred_ptr, expected_udc, 64); + vpx_memset(vpred_ptr, expected_vdc, 64); + + + } + break; + case V_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memcpy(upred_ptr, uabove_row, 8); + vpx_memcpy(vpred_ptr, vabove_row, 8); + upred_ptr += 8; + vpred_ptr += 8; + } + + } + break; + case H_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memset(upred_ptr, uleft_col[i], 8); + vpx_memset(vpred_ptr, vleft_col[i], 8); + upred_ptr += 8; + vpred_ptr += 8; + } + } + + break; + case TM_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + int predu = uleft_col[i] + uabove_row[j] - utop_left; + int predv = vleft_col[i] + vabove_row[j] - vtop_left; + + if (predu < 0) + predu = 0; + + if (predu > 255) + predu = 255; + + if (predv < 0) + predv = 0; + + if (predv > 255) + predv = 255; + + upred_ptr[j] = predu; + vpred_ptr[j] = predv; + } + + upred_ptr += 8; + vpred_ptr += 8; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +} + +void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x) +{ + unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; + unsigned char uleft_col[16]; + unsigned char utop_left = uabove_row[-1]; + unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; + unsigned char vleft_col[20]; + unsigned char vtop_left = vabove_row[-1]; + unsigned char *upred_ptr = x->dst.u_buffer; //&x->predictor[256]; + unsigned char *vpred_ptr = x->dst.v_buffer; //&x->predictor[320]; + int uv_stride = x->dst.uv_stride; + + int i, j; + + for (i = 0; i < 8; i++) + { + uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; + vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; + } + + switch (x->mbmi.uv_mode) + { + case DC_PRED: + { + int expected_udc; + int expected_vdc; + int i; + int shift; + int Uaverage = 0; + int Vaverage = 0; + + if (x->up_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uabove_row[i]; + Vaverage += vabove_row[i]; + } + } + + if (x->left_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uleft_col[i]; + Vaverage += vleft_col[i]; + } + } + + if (!x->up_available && !x->left_available) + { + expected_udc = 128; + expected_vdc = 128; + } + else + { + shift = 2 + x->up_available + x->left_available; + expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; + expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; + } + + + //vpx_memset(upred_ptr,expected_udc,64); + //vpx_memset(vpred_ptr,expected_vdc,64); + for (i = 0; i < 8; i++) + { + vpx_memset(upred_ptr, expected_udc, 8); + vpx_memset(vpred_ptr, expected_vdc, 8); + upred_ptr += uv_stride; //8; + vpred_ptr += uv_stride; //8; + } + } + break; + case V_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memcpy(upred_ptr, uabove_row, 8); + vpx_memcpy(vpred_ptr, vabove_row, 8); + upred_ptr += uv_stride; //8; + vpred_ptr += uv_stride; //8; + } + + } + break; + case H_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + vpx_memset(upred_ptr, uleft_col[i], 8); + vpx_memset(vpred_ptr, vleft_col[i], 8); + upred_ptr += uv_stride; //8; + vpred_ptr += uv_stride; //8; + } + } + + break; + case TM_PRED: + { + int i; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + int predu = uleft_col[i] + uabove_row[j] - utop_left; + int predv = vleft_col[i] + vabove_row[j] - vtop_left; + + if (predu < 0) + predu = 0; + + if (predu > 255) + predu = 255; + + if (predv < 0) + predv = 0; + + if (predv > 255) + predv = 255; + + upred_ptr[j] = predu; + vpred_ptr[j] = predv; + } + + upred_ptr += uv_stride; //8; + vpred_ptr += uv_stride; //8; + } + + } + break; + case B_PRED: + case NEARESTMV: + case NEARMV: + case ZEROMV: + case NEWMV: + case SPLITMV: + case MB_MODE_COUNT: + break; + } +}
diff --git a/vp8/common/reconintra.h b/vp8/common/reconintra.h new file mode 100644 index 0000000..d63aa15 --- /dev/null +++ b/vp8/common/reconintra.h
@@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_RECONINTRA_H +#define __INC_RECONINTRA_H + +extern void init_intra_left_above_pixels(MACROBLOCKD *x); + +extern void (*vp8_build_intra_predictors_mby_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_neon(MACROBLOCKD *x); +extern void (*vp8_build_intra_predictors_mby_s_ptr)(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_s(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mby_s_neon(MACROBLOCKD *x); + +extern void vp8_build_intra_predictors_mbuv(MACROBLOCKD *x); +extern void vp8_build_intra_predictors_mbuv_s(MACROBLOCKD *x); + +extern void vp8_predict_intra4x4(BLOCKD *x, int b_mode, unsigned char *Predictor); + +#endif
diff --git a/vp8/common/reconintra4x4.c b/vp8/common/reconintra4x4.c new file mode 100644 index 0000000..d92d5c9 --- /dev/null +++ b/vp8/common/reconintra4x4.c
@@ -0,0 +1,330 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "recon.h" +#include "vpx_mem/vpx_mem.h" +#include "reconintra.h" + +void vp8_predict_intra4x4(BLOCKD *x, + int b_mode, + unsigned char *predictor) +{ + int i, r, c; + + unsigned char *Above = *(x->base_dst) + x->dst - x->dst_stride; + unsigned char Left[4]; + unsigned char top_left = Above[-1]; + + Left[0] = (*(x->base_dst))[x->dst - 1]; + Left[1] = (*(x->base_dst))[x->dst - 1 + x->dst_stride]; + Left[2] = (*(x->base_dst))[x->dst - 1 + 2 * x->dst_stride]; + Left[3] = (*(x->base_dst))[x->dst - 1 + 3 * x->dst_stride]; + + switch (b_mode) + { + case B_DC_PRED: + { + int expected_dc = 0; + + for (i = 0; i < 4; i++) + { + expected_dc += Above[i]; + expected_dc += Left[i]; + } + + expected_dc = (expected_dc + 4) >> 3; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = expected_dc; + } + + predictor += 16; + } + } + break; + case B_TM_PRED: + { + // prediction similar to true_motion prediction + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int pred = Above[c] - top_left + Left[r]; + + if (pred < 0) + pred = 0; + + if (pred > 255) + pred = 255; + + predictor[c] = pred; + } + + predictor += 16; + } + } + break; + + case B_VE_PRED: + { + + unsigned int ap[4]; + ap[0] = (top_left + 2 * Above[0] + Above[1] + 2) >> 2; + ap[1] = (Above[0] + 2 * Above[1] + Above[2] + 2) >> 2; + ap[2] = (Above[1] + 2 * Above[2] + Above[3] + 2) >> 2; + ap[3] = (Above[2] + 2 * Above[3] + Above[4] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + + predictor[c] = ap[c]; + } + + predictor += 16; + } + + } + break; + + + case B_HE_PRED: + { + + unsigned int lp[4]; + lp[0] = (top_left + 2 * Left[0] + Left[1] + 2) >> 2; + lp[1] = (Left[0] + 2 * Left[1] + Left[2] + 2) >> 2; + lp[2] = (Left[1] + 2 * Left[2] + Left[3] + 2) >> 2; + lp[3] = (Left[2] + 2 * Left[3] + Left[3] + 2) >> 2; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + predictor[c] = lp[r]; + } + + predictor += 16; + } + } + break; + case B_LD_PRED: + { + unsigned char *ptr = Above; + predictor[0 * 16 + 0] = (ptr[0] + ptr[1] * 2 + ptr[2] + 2) >> 2; + predictor[0 * 16 + 1] = + predictor[1 * 16 + 0] = (ptr[1] + ptr[2] * 2 + ptr[3] + 2) >> 2; + predictor[0 * 16 + 2] = + predictor[1 * 16 + 1] = + predictor[2 * 16 + 0] = (ptr[2] + ptr[3] * 2 + ptr[4] + 2) >> 2; + predictor[0 * 16 + 3] = + predictor[1 * 16 + 2] = + predictor[2 * 16 + 1] = + predictor[3 * 16 + 0] = (ptr[3] + ptr[4] * 2 + ptr[5] + 2) >> 2; + predictor[1 * 16 + 3] = + predictor[2 * 16 + 2] = + predictor[3 * 16 + 1] = (ptr[4] + ptr[5] * 2 + ptr[6] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[3 * 16 + 2] = (ptr[5] + ptr[6] * 2 + ptr[7] + 2) >> 2; + predictor[3 * 16 + 3] = (ptr[6] + ptr[7] * 2 + ptr[7] + 2) >> 2; + + } + break; + case B_RD_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + predictor[3 * 16 + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[3 * 16 + 1] = + predictor[2 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[3 * 16 + 2] = + predictor[2 * 16 + 1] = + predictor[1 * 16 + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[3 * 16 + 3] = + predictor[2 * 16 + 2] = + predictor[1 * 16 + 1] = + predictor[0 * 16 + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[1 * 16 + 2] = + predictor[0 * 16 + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[1 * 16 + 3] = + predictor[0 * 16 + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + + } + break; + case B_VR_PRED: + { + + unsigned char pp[9]; + + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + predictor[3 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 0] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[3 * 16 + 1] = + predictor[1 * 16 + 0] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 1] = + predictor[0 * 16 + 0] = (pp[4] + pp[5] + 1) >> 1; + predictor[3 * 16 + 2] = + predictor[1 * 16 + 1] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[0 * 16 + 1] = (pp[5] + pp[6] + 1) >> 1; + predictor[3 * 16 + 3] = + predictor[1 * 16 + 2] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + predictor[2 * 16 + 3] = + predictor[0 * 16 + 2] = (pp[6] + pp[7] + 1) >> 1; + predictor[1 * 16 + 3] = (pp[6] + pp[7] * 2 + pp[8] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[7] + pp[8] + 1) >> 1; + + } + break; + case B_VL_PRED: + { + + unsigned char *pp = Above; + + predictor[0 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[1 * 16 + 0] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[2 * 16 + 0] = + predictor[0 * 16 + 1] = (pp[1] + pp[2] + 1) >> 1; + predictor[1 * 16 + 1] = + predictor[3 * 16 + 0] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 1] = + predictor[0 * 16 + 2] = (pp[2] + pp[3] + 1) >> 1; + predictor[3 * 16 + 1] = + predictor[1 * 16 + 2] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[0 * 16 + 3] = + predictor[2 * 16 + 2] = (pp[3] + pp[4] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[3 * 16 + 2] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[2 * 16 + 3] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[3 * 16 + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + case B_HD_PRED: + { + unsigned char pp[9]; + pp[0] = Left[3]; + pp[1] = Left[2]; + pp[2] = Left[1]; + pp[3] = Left[0]; + pp[4] = top_left; + pp[5] = Above[0]; + pp[6] = Above[1]; + pp[7] = Above[2]; + pp[8] = Above[3]; + + + predictor[3 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[3 * 16 + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[2 * 16 + 0] = + predictor[3 * 16 + 2] = (pp[1] + pp[2] + 1) >> 1; + predictor[2 * 16 + 1] = + predictor[3 * 16 + 3] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[1 * 16 + 0] = (pp[2] + pp[3] + 1) >> 1; + predictor[2 * 16 + 3] = + predictor[1 * 16 + 1] = (pp[2] + pp[3] * 2 + pp[4] + 2) >> 2; + predictor[1 * 16 + 2] = + predictor[0 * 16 + 0] = (pp[3] + pp[4] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[0 * 16 + 1] = (pp[3] + pp[4] * 2 + pp[5] + 2) >> 2; + predictor[0 * 16 + 2] = (pp[4] + pp[5] * 2 + pp[6] + 2) >> 2; + predictor[0 * 16 + 3] = (pp[5] + pp[6] * 2 + pp[7] + 2) >> 2; + } + break; + + + case B_HU_PRED: + { + unsigned char *pp = Left; + predictor[0 * 16 + 0] = (pp[0] + pp[1] + 1) >> 1; + predictor[0 * 16 + 1] = (pp[0] + pp[1] * 2 + pp[2] + 2) >> 2; + predictor[0 * 16 + 2] = + predictor[1 * 16 + 0] = (pp[1] + pp[2] + 1) >> 1; + predictor[0 * 16 + 3] = + predictor[1 * 16 + 1] = (pp[1] + pp[2] * 2 + pp[3] + 2) >> 2; + predictor[1 * 16 + 2] = + predictor[2 * 16 + 0] = (pp[2] + pp[3] + 1) >> 1; + predictor[1 * 16 + 3] = + predictor[2 * 16 + 1] = (pp[2] + pp[3] * 2 + pp[3] + 2) >> 2; + predictor[2 * 16 + 2] = + predictor[2 * 16 + 3] = + predictor[3 * 16 + 0] = + predictor[3 * 16 + 1] = + predictor[3 * 16 + 2] = + predictor[3 * 16 + 3] = pp[3]; + } + break; + + + } +} +// copy 4 bytes from the above right down so that the 4x4 prediction modes using pixels above and +// to the right prediction have filled in pixels to use. +void vp8_intra_prediction_down_copy(MACROBLOCKD *x) +{ + unsigned char *above_right = *(x->block[0].base_dst) + x->block[0].dst - x->block[0].dst_stride + 16; + + unsigned int *src_ptr = (unsigned int *)above_right; + unsigned int *dst_ptr0 = (unsigned int *)(above_right + 4 * x->block[0].dst_stride); + unsigned int *dst_ptr1 = (unsigned int *)(above_right + 8 * x->block[0].dst_stride); + unsigned int *dst_ptr2 = (unsigned int *)(above_right + 12 * x->block[0].dst_stride); + + *dst_ptr0 = *src_ptr; + *dst_ptr1 = *src_ptr; + *dst_ptr2 = *src_ptr; +} + + +void vp8_recon_intra4x4mb(const vp8_recon_rtcd_vtable_t *rtcd, MACROBLOCKD *x) +{ + int i; + + vp8_intra_prediction_down_copy(x); + + for (i = 0; i < 16; i++) + { + BLOCKD *b = &x->block[i]; + + vp8_predict_intra4x4(b, x->block[i].bmi.mode, x->block[i].predictor); + RECON_INVOKE(rtcd, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); + } + + vp8_recon_intra_mbuv(rtcd, x); + +}
diff --git a/vp8/common/reconintra4x4.h b/vp8/common/reconintra4x4.h new file mode 100644 index 0000000..788c8c4 --- /dev/null +++ b/vp8/common/reconintra4x4.h
@@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_RECONINTRA4x4_H +#define __INC_RECONINTRA4x4_H + +extern void vp8_intra_prediction_down_copy(MACROBLOCKD *x); + +#endif
diff --git a/vp8/common/segmentation_common.c b/vp8/common/segmentation_common.c new file mode 100644 index 0000000..72b8c87 --- /dev/null +++ b/vp8/common/segmentation_common.c
@@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "segmentation_common.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_update_gf_useage_maps(VP8_COMMON *cm, MACROBLOCKD *xd) +{ + int mb_row, mb_col; + + MODE_INFO *this_mb_mode_info = cm->mi; + + xd->gf_active_ptr = (signed char *)cm->gf_active_flags; + + if ((cm->frame_type == KEY_FRAME) || (cm->refresh_golden_frame)) + { + // Reset Gf useage monitors + vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cm->gf_active_count = cm->mb_rows * cm->mb_cols; + } + else + { + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + + // If using golden then set GF active flag if not already set. + // If using last frame 0,0 mode then leave flag as it is + // else if using non 0,0 motion or intra modes then clear flag if it is currently set + if ((this_mb_mode_info->mbmi.ref_frame == GOLDEN_FRAME) || (this_mb_mode_info->mbmi.ref_frame == ALTREF_FRAME)) + { + if (*(xd->gf_active_ptr) == 0) + { + *(xd->gf_active_ptr) = 1; + cm->gf_active_count ++; + } + } + else if ((this_mb_mode_info->mbmi.mode != ZEROMV) && *(xd->gf_active_ptr)) + { + *(xd->gf_active_ptr) = 0; + cm->gf_active_count--; + } + + xd->gf_active_ptr++; // Step onto next entry + this_mb_mode_info++; // skip to next mb + + } + + // this is to account for the border + this_mb_mode_info++; + } + } +}
diff --git a/vp8/common/segmentation_common.h b/vp8/common/segmentation_common.h new file mode 100644 index 0000000..bb93533 --- /dev/null +++ b/vp8/common/segmentation_common.h
@@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "string.h" +#include "blockd.h" +#include "onyxc_int.h" + +extern void vp8_update_gf_useage_maps(VP8_COMMON *cm, MACROBLOCKD *xd);
diff --git a/vp8/common/setupintrarecon.c b/vp8/common/setupintrarecon.c new file mode 100644 index 0000000..dcaafe6 --- /dev/null +++ b/vp8/common/setupintrarecon.c
@@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "setupintrarecon.h" +#include "vpx_mem/vpx_mem.h" + +void vp8_setup_intra_recon(YV12_BUFFER_CONFIG *ybf) +{ + int i; + + // set up frame new frame for intra coded blocks + vpx_memset(ybf->y_buffer - 1 - 2 * ybf->y_stride, 127, ybf->y_width + 5); + vpx_memset(ybf->y_buffer - 1 - ybf->y_stride, 127, ybf->y_width + 5); + + for (i = 0; i < ybf->y_height; i++) + ybf->y_buffer[ybf->y_stride *i - 1] = (unsigned char) 129; + + vpx_memset(ybf->u_buffer - 1 - 2 * ybf->uv_stride, 127, ybf->uv_width + 5); + vpx_memset(ybf->u_buffer - 1 - ybf->uv_stride, 127, ybf->uv_width + 5); + + for (i = 0; i < ybf->uv_height; i++) + ybf->u_buffer[ybf->uv_stride *i - 1] = (unsigned char) 129; + + vpx_memset(ybf->v_buffer - 1 - 2 * ybf->uv_stride, 127, ybf->uv_width + 5); + vpx_memset(ybf->v_buffer - 1 - ybf->uv_stride, 127, ybf->uv_width + 5); + + for (i = 0; i < ybf->uv_height; i++) + ybf->v_buffer[ybf->uv_stride *i - 1] = (unsigned char) 129; + +}
diff --git a/vp8/common/setupintrarecon.h b/vp8/common/setupintrarecon.h new file mode 100644 index 0000000..6ec79b2 --- /dev/null +++ b/vp8/common/setupintrarecon.h
@@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +extern void vp8_setup_intra_recon(YV12_BUFFER_CONFIG *ybf);
diff --git a/vp8/common/subpixel.h b/vp8/common/subpixel.h new file mode 100644 index 0000000..fbd5f4d --- /dev/null +++ b/vp8/common/subpixel.h
@@ -0,0 +1,85 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef SUBPIXEL_H +#define SUBPIXEL_H + +#define prototype_subpixel_predict(sym) \ + void sym(unsigned char *src, int src_pitch, int xofst, int yofst, \ + unsigned char *dst, int dst_pitch) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/subpixel_x86.h" +#endif + +#if ARCH_ARM +#include "arm/subpixel_arm.h" +#endif + +#ifndef vp8_subpix_sixtap16x16 +#define vp8_subpix_sixtap16x16 vp8_sixtap_predict16x16_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap16x16); + +#ifndef vp8_subpix_sixtap8x8 +#define vp8_subpix_sixtap8x8 vp8_sixtap_predict8x8_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap8x8); + +#ifndef vp8_subpix_sixtap8x4 +#define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap8x4); + +#ifndef vp8_subpix_sixtap4x4 +#define vp8_subpix_sixtap4x4 vp8_sixtap_predict_c +#endif +extern prototype_subpixel_predict(vp8_subpix_sixtap4x4); + +#ifndef vp8_subpix_bilinear16x16 +#define vp8_subpix_bilinear16x16 vp8_bilinear_predict16x16_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear16x16); + +#ifndef vp8_subpix_bilinear8x8 +#define vp8_subpix_bilinear8x8 vp8_bilinear_predict8x8_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear8x8); + +#ifndef vp8_subpix_bilinear8x4 +#define vp8_subpix_bilinear8x4 vp8_bilinear_predict8x4_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear8x4); + +#ifndef vp8_subpix_bilinear4x4 +#define vp8_subpix_bilinear4x4 vp8_bilinear_predict4x4_c +#endif +extern prototype_subpixel_predict(vp8_subpix_bilinear4x4); + +typedef prototype_subpixel_predict((*vp8_subpix_fn_t)); +typedef struct +{ + vp8_subpix_fn_t sixtap16x16; + vp8_subpix_fn_t sixtap8x8; + vp8_subpix_fn_t sixtap8x4; + vp8_subpix_fn_t sixtap4x4; + vp8_subpix_fn_t bilinear16x16; + vp8_subpix_fn_t bilinear8x8; + vp8_subpix_fn_t bilinear8x4; + vp8_subpix_fn_t bilinear4x4; +} vp8_subpix_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define SUBPIX_INVOKE(ctx,fn) (ctx)->fn +#else +#define SUBPIX_INVOKE(ctx,fn) vp8_subpix_##fn +#endif + +#endif
diff --git a/vp8/common/swapyv12buffer.c b/vp8/common/swapyv12buffer.c new file mode 100644 index 0000000..afe6a88 --- /dev/null +++ b/vp8/common/swapyv12buffer.c
@@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "swapyv12buffer.h" + +void vp8_swap_yv12_buffer(YV12_BUFFER_CONFIG *new_frame, YV12_BUFFER_CONFIG *last_frame) +{ + unsigned char *temp; + + temp = last_frame->buffer_alloc; + last_frame->buffer_alloc = new_frame->buffer_alloc; + new_frame->buffer_alloc = temp; + + temp = last_frame->y_buffer; + last_frame->y_buffer = new_frame->y_buffer; + new_frame->y_buffer = temp; + + temp = last_frame->u_buffer; + last_frame->u_buffer = new_frame->u_buffer; + new_frame->u_buffer = temp; + + temp = last_frame->v_buffer; + last_frame->v_buffer = new_frame->v_buffer; + new_frame->v_buffer = temp; + +}
diff --git a/vp8/common/swapyv12buffer.h b/vp8/common/swapyv12buffer.h new file mode 100644 index 0000000..caf9499 --- /dev/null +++ b/vp8/common/swapyv12buffer.h
@@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef SWAPYV12_BUFFER_H +#define SWAPYV12_BUFFER_H + +#include "vpx_scale/yv12config.h" + +void vp8_swap_yv12_buffer(YV12_BUFFER_CONFIG *new_frame, YV12_BUFFER_CONFIG *last_frame); + +#endif
diff --git a/vp8/common/systemdependent.h b/vp8/common/systemdependent.h new file mode 100644 index 0000000..1829b64 --- /dev/null +++ b/vp8/common/systemdependent.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#if ARCH_X86 || ARCH_X86_64 +void vpx_reset_mmx_state(void); +#define vp8_clear_system_state() vpx_reset_mmx_state() +#else +#define vp8_clear_system_state() +#endif + +struct VP8Common; +void vp8_machine_specific_config(struct VP8Common *);
diff --git a/vp8/common/textblit.c b/vp8/common/textblit.c new file mode 100644 index 0000000..a45937b --- /dev/null +++ b/vp8/common/textblit.c
@@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + + + +void vp8_blit_text(const char *msg, unsigned char *address, const int pitch) +{ + int letter_bitmap; + unsigned char *output_pos = address; + int colpos; + const int font[] = + { + 0x0, 0x5C00, 0x8020, 0xAFABEA, 0xD7EC0, 0x1111111, 0x1855740, 0x18000, + 0x45C0, 0x74400, 0x51140, 0x23880, 0xC4000, 0x21080, 0x80000, 0x111110, + 0xE9D72E, 0x87E40, 0x12AD732, 0xAAD62A, 0x4F94C4, 0x4D6B7, 0x456AA, + 0x3E8423, 0xAAD6AA, 0xAAD6A2, 0x2800, 0x2A00, 0x8A880, 0x52940, 0x22A20, + 0x15422, 0x6AD62E, 0x1E4A53E, 0xAAD6BF, 0x8C62E, 0xE8C63F, 0x118D6BF, + 0x1094BF, 0xCAC62E, 0x1F2109F, 0x118FE31, 0xF8C628, 0x8A89F, 0x108421F, + 0x1F1105F, 0x1F4105F, 0xE8C62E, 0x2294BF, 0x164C62E, 0x12694BF, 0x8AD6A2, + 0x10FC21, 0x1F8421F, 0x744107, 0xF8220F, 0x1151151, 0x117041, 0x119D731, + 0x47E0, 0x1041041, 0xFC400, 0x10440, 0x1084210, 0x820 + }; + colpos = 0; + + while (msg[colpos] != 0) + { + char letter = msg[colpos]; + int fontcol, fontrow; + + if (letter <= 'Z' && letter >= ' ') + letter_bitmap = font[letter-' ']; + else if (letter <= 'z' && letter >= 'a') + letter_bitmap = font[letter-'a'+'A' - ' ']; + else + letter_bitmap = font[0]; + + for (fontcol = 6; fontcol >= 0 ; fontcol--) + for (fontrow = 0; fontrow < 5; fontrow++) + output_pos[fontrow *pitch + fontcol] = + ((letter_bitmap >> (fontcol * 5)) & (1 << fontrow) ? 255 : 0); + + output_pos += 7; + colpos++; + } +}
diff --git a/vp8/common/threading.h b/vp8/common/threading.h new file mode 100644 index 0000000..a02cb24 --- /dev/null +++ b/vp8/common/threading.h
@@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _PTHREAD_EMULATION +#define _PTHREAD_EMULATION + +#define VPXINFINITE 10000 //10second. + +/* Thread management macros */ +#ifdef _WIN32 +/* Win32 */ +#define _WIN32_WINNT 0x500 /* WINBASE.H - Enable signal_object_and_wait */ +#include <process.h> +#include <windows.h> +#define THREAD_FUNCTION DWORD WINAPI +#define THREAD_FUNCTION_RETURN DWORD +#define THREAD_SPECIFIC_INDEX DWORD +#define pthread_t HANDLE +#define pthread_attr_t DWORD +#define pthread_create(thhandle,attr,thfunc,tharg) (int)((*thhandle=(HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall *)(void *))thfunc,tharg,0,NULL))==NULL) +#define pthread_join(thread, result) ((WaitForSingleObject((thread),VPXINFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread)) +#define pthread_detach(thread) if(thread!=NULL)CloseHandle(thread) +#define thread_sleep(nms) Sleep(nms) +#define pthread_cancel(thread) terminate_thread(thread,0) +#define ts_key_create(ts_key, destructor) {ts_key = TlsAlloc();}; +#define pthread_getspecific(ts_key) TlsGetValue(ts_key) +#define pthread_setspecific(ts_key, value) TlsSetValue(ts_key, (void *)value) +#define pthread_self() GetCurrentThreadId() +#else +#ifdef __APPLE__ +#include <mach/semaphore.h> +#include <mach/task.h> +#include <time.h> +#include <unistd.h> + +#else +#include <semaphore.h> +#endif + +#include <pthread.h> +/* pthreads */ +/* Nearly everything is already defined */ +#define THREAD_FUNCTION void * +#define THREAD_FUNCTION_RETURN void * +#define THREAD_SPECIFIC_INDEX pthread_key_t +#define ts_key_create(ts_key, destructor) pthread_key_create (&(ts_key), destructor); +#endif + +/* Syncrhronization macros: Win32 and Pthreads */ +#ifdef _WIN32 +#define sem_t HANDLE +#define pause(voidpara) __asm PAUSE +#define sem_init(sem, sem_attr1, sem_init_value) (int)((*sem = CreateEvent(NULL,FALSE,FALSE,NULL))==NULL) +#define sem_wait(sem) (int)(WAIT_OBJECT_0 != WaitForSingleObject(*sem,VPXINFINITE)) +#define sem_post(sem) SetEvent(*sem) +#define sem_destroy(sem) if(*sem)((int)(CloseHandle(*sem))==TRUE) +#define thread_sleep(nms) Sleep(nms) + +#else + +#ifdef __APPLE__ +#define sem_t semaphore_t +#define sem_init(X,Y,Z) semaphore_create(mach_task_self(), X, SYNC_POLICY_FIFO, Z) +#define sem_wait(sem) (semaphore_wait(*sem) ) +#define sem_post(sem) semaphore_signal(*sem) +#define sem_destroy(sem) semaphore_destroy(mach_task_self(),*sem) +#define thread_sleep(nms) // { struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} +#else +#include <unistd.h> +#define thread_sleep(nms) usleep(nms*1000);// {struct timespec ts;ts.tv_sec=0; ts.tv_nsec = 1000*nms;nanosleep(&ts, NULL);} +#endif +/* Not Windows. Assume pthreads */ + +#endif + +#if ARCH_X86 || ARCH_X86_64 +#include "vpx_ports/x86.h" +#else +#define x86_pause_hint() +#endif + +#endif
diff --git a/vp8/common/treecoder.c b/vp8/common/treecoder.c new file mode 100644 index 0000000..4ad018d --- /dev/null +++ b/vp8/common/treecoder.c
@@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if CONFIG_DEBUG +#include <assert.h> +#endif +#include <stdio.h> + +#include "treecoder.h" + +static void tree2tok( + struct vp8_token_struct *const p, + vp8_tree t, + int i, + int v, + int L +) +{ + v += v; + ++L; + + do + { + const vp8_tree_index j = t[i++]; + + if (j <= 0) + { + p[-j].value = v; + p[-j].Len = L; + } + else + tree2tok(p, t, j, v, L); + } + while (++v & 1); +} + +void vp8_tokens_from_tree(struct vp8_token_struct *p, vp8_tree t) +{ + tree2tok(p, t, 0, 0, 0); +} + +static void branch_counts( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ] +) +{ + const int tree_len = n - 1; + int t = 0; + +#if CONFIG_DEBUG + assert(tree_len); +#endif + + do + { + branch_ct[t][0] = branch_ct[t][1] = 0; + } + while (++t < tree_len); + + t = 0; + + do + { + int L = tok[t].Len; + const int enc = tok[t].value; + const unsigned int ct = num_events[t]; + + vp8_tree_index i = 0; + + do + { + const int b = (enc >> --L) & 1; + const int j = i >> 1; +#if CONFIG_DEBUG + assert(j < tree_len && 0 <= L); +#endif + + branch_ct [j] [b] += ct; + i = tree[ i + b]; + } + while (i > 0); + +#if CONFIG_DEBUG + assert(!L); +#endif + } + while (++t < n); + +} + + +void vp8_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + unsigned int Pfac, + int rd +) +{ + const int tree_len = n - 1; + int t = 0; + + branch_counts(n, tok, tree, branch_ct, num_events); + + do + { + const unsigned int *const c = branch_ct[t]; + const unsigned int tot = c[0] + c[1]; + +#if CONFIG_DEBUG + assert(tot < (1 << 24)); /* no overflow below */ +#endif + + if (tot) + { + const unsigned int p = ((c[0] * Pfac) + (rd ? tot >> 1 : 0)) / tot; + probs[t] = p < 256 ? (p ? p : 1) : 255; /* agree w/old version for now */ + } + else + probs[t] = vp8_prob_half; + } + while (++t < tree_len); +}
diff --git a/vp8/common/treecoder.h b/vp8/common/treecoder.h new file mode 100644 index 0000000..0356d2b --- /dev/null +++ b/vp8/common/treecoder.h
@@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_TREECODER_H +#define __INC_TREECODER_H + +typedef unsigned char vp8bc_index_t; // probability index + + +typedef unsigned char vp8_prob; + +#define vp8_prob_half ( (vp8_prob) 128) + +typedef signed char vp8_tree_index; +struct bool_coder_spec; + +typedef struct bool_coder_spec bool_coder_spec; +typedef struct bool_writer bool_writer; +typedef struct bool_reader bool_reader; + +typedef const bool_coder_spec c_bool_coder_spec; +typedef const bool_writer c_bool_writer; +typedef const bool_reader c_bool_reader; + + + +# define vp8_complement( x) (255 - x) + + +/* We build coding trees compactly in arrays. + Each node of the tree is a pair of vp8_tree_indices. + Array index often references a corresponding probability table. + Index <= 0 means done encoding/decoding and value = -Index, + Index > 0 means need another bit, specification at index. + Nonnegative indices are always even; processing begins at node 0. */ + +typedef const vp8_tree_index vp8_tree[], *vp8_tree_p; + + +typedef const struct vp8_token_struct +{ + int value; + int Len; +} vp8_token; + +/* Construct encoding array from tree. */ + +void vp8_tokens_from_tree(struct vp8_token_struct *, vp8_tree); + + +/* Convert array of token occurrence counts into a table of probabilities + for the associated binary encoding tree. Also writes count of branches + taken for each node on the tree; this facilitiates decisions as to + probability updates. */ + +void vp8_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + unsigned int Pfactor, + int Round +); + +/* Variant of above using coder spec rather than hardwired 8-bit probs. */ + +void vp8bc_tree_probs_from_distribution( + int n, /* n = size of alphabet */ + vp8_token tok [ /* n */ ], + vp8_tree tree, + vp8_prob probs [ /* n-1 */ ], + unsigned int branch_ct [ /* n-1 */ ] [2], + const unsigned int num_events[ /* n */ ], + c_bool_coder_spec *s +); + + +#endif
diff --git a/vp8/common/type_aliases.h b/vp8/common/type_aliases.h new file mode 100644 index 0000000..addd264 --- /dev/null +++ b/vp8/common/type_aliases.h
@@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : type_aliases.h +* +* Description : Standard type aliases +* +****************************************************************************/ +#ifndef __INC_TYPE_ALIASES_H +#define __INC_TYPE_ALIASES_H + +/**************************************************************************** +* Macros +****************************************************************************/ +#define EXPORT +#define IMPORT extern /* Used to declare imported data & routines */ +#define PRIVATE static /* Used to declare & define module-local data */ +#define LOCAL static /* Used to define all persistent routine-local data */ +#define STD_IN_PATH 0 /* Standard input path */ +#define STD_OUT_PATH 1 /* Standard output path */ +#define STD_ERR_PATH 2 /* Standard error path */ +#define STD_IN_FILE stdin /* Standard input file pointer */ +#define STD_OUT_FILE stdout /* Standard output file pointer */ +#define STD_ERR_FILE stderr /* Standard error file pointer */ +#define max_int 0x7FFFFFFF + +#define __export +#define _export + +#define CCONV + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/**************************************************************************** +* Typedefs +****************************************************************************/ +#ifndef TYPE_INT8 +#define TYPE_INT8 +typedef signed char INT8; +#endif + +#ifndef TYPE_INT16 +//#define TYPE_INT16 +typedef signed short INT16; +#endif + +#ifndef TYPE_INT32 +//#define TYPE_INT32 +typedef signed int INT32; +#endif + +#ifndef TYPE_UINT8 +//#define TYPE_UINT8 +typedef unsigned char UINT8; +#endif + +#ifndef TYPE_UINT32 +//#define TYPE_UINT32 +typedef unsigned int UINT32; +#endif + +#ifndef TYPE_UINT16 +//#define TYPE_UINT16 +typedef unsigned short UINT16; +#endif + +#ifndef TYPE_BOOL +//#define TYPE_BOOL +typedef int BOOL; +#endif + +typedef unsigned char BOOLEAN; + +#ifdef _MSC_VER +typedef __int64 INT64; +#else + +#ifndef TYPE_INT64 +#ifdef _TMS320C6X +//for now we only have 40bits +typedef long INT64; +#else +typedef long long INT64; +#endif +#endif + +#endif + +/* Floating point */ +typedef double FLOAT64; +typedef float FLOAT32; + +#endif
diff --git a/vp8/common/vfwsetting.hpp b/vp8/common/vfwsetting.hpp new file mode 100644 index 0000000..e352e7a --- /dev/null +++ b/vp8/common/vfwsetting.hpp
@@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if !defined(VFWSETTING_HPP) +#define VFWSETTING_HPP +//______________________________________________________________________________ +// +// VFWSetting.hpp +// + +#include "four_cc.hpp" +#include <iosfwd> + +namespace vpxvp +{ + + //-------------------------------------- + class VFWSetting + { + friend std::ostream& operator<<(std::ostream& os, const VFWSetting& vfws); + + public: + + enum Mode + { + m_setting, + m_config + }; + + enum + { + header_size = 8, + Size = 16 + }; + + VFWSetting(four_cc fcc); + ~VFWSetting(); + + four_cc fcc() const; + Mode mode() const; + + int setting() const; + int value() const; + void setting_value(int i_setting, int i_value); // Sets mode to m_setting + + long size() const; + const void* data() const; + int data(const void* p_data, unsigned long ul_size); + + private: + + VFWSetting(const VFWSetting& vfws); // Not implemented + VFWSetting& operator=(const VFWSetting& vfws); // Not implemented + + int extract_(const void* p_data, unsigned long ul_size); + void update_() const; + + four_cc m_fcc; + Mode m_mode; + int m_i_setting; + int m_i_value; + + mutable unsigned char m_p_data[Size]; + }; + +} // namespace vpxvp + +#endif // VFWSETTING_HPP
diff --git a/vp8/common/vpx_ref_build_prefix.h b/vp8/common/vpx_ref_build_prefix.h new file mode 100644 index 0000000..40608c6 --- /dev/null +++ b/vp8/common/vpx_ref_build_prefix.h
@@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _VPX_REF_BUILD_PREFIX_h +#define _VPX_REF_BUILD_PREFIX_h + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(__cplusplus) +} +#endif + +#endif /* include guards */
diff --git a/vp8/common/vpxblit.h b/vp8/common/vpxblit.h new file mode 100644 index 0000000..d03e0bd --- /dev/null +++ b/vp8/common/vpxblit.h
@@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef VPXBLIT_H_INCL +#define VPXBLIT_H_INCL +/*============================================================================== + Includes +==============================================================================*/ + +/*============================================================================== + Defines +==============================================================================*/ + + +#ifdef VPX_BIG_ENDIAN +#define BYTE_ZERO(X) ((X & 0xFF000000) >> (24 - 2) ) +#define BYTE_ONE(X) ((X & 0x00FF0000) >> (16 - 2) ) +#define BYTE_TWO(X) ((X & 0x0000FF00) >> (8 - 2) ) +#define BYTE_THREE(X) ((X & 0x000000FF) << (0 + 2) ) + +#define BYTE_ZERO_UV(X) ((X & 0x0000FF00) >> (8 - 2) ) +#define BYTE_ONE_UV(X) ((X & 0x000000FF) << (0 + 2) ) + +#define REREFERENCE(X) (*((int *) &(X))) + +#else + +#define BYTE_THREE(X) ((X & 0xFF000000) >> (24 - 2) ) +#define BYTE_TWO(X) ((X & 0x00FF0000) >> (16 - 2) ) +#define BYTE_ONE(X) ((X & 0x0000FF00) >> (8 - 2) ) +#define BYTE_ZERO(X) ((X & 0x000000FF) << (0 + 2) ) + +#define BYTE_ONE_UV(X) ((X & 0x0000FF00) >> (8 - 2) ) +#define BYTE_ZERO_UV(X) ((X & 0x000000FF) << (0 + 2) ) + +#define REREFERENCE(X) (*((int *) &(X))) + +#endif + + +/*============================================================================== + Type Definitions +==============================================================================*/ +typedef struct // YUV buffer configuration structure +{ + int y_width; + int y_height; + int y_stride; + + int uv_width; + int uv_height; + int uv_stride; + + char *y_buffer; + char *u_buffer; + char *v_buffer; + + char *uv_start; + int uv_dst_area; + int uv_used_area; + +} VPX_BLIT_CONFIG; + +typedef struct tx86_params +{ + unsigned int pushed_registers[6]; + unsigned int return_address; + unsigned int dst; + unsigned int scrn_pitch; + VPX_BLIT_CONFIG *buff_config; +} x86_params; + +/*============================================================================= + Enums +==============================================================================*/ + + +/*============================================================================== + Structures +==============================================================================*/ + +/*============================================================================== + Constants +==============================================================================*/ + + +/*============================================================================== + Variables +==============================================================================*/ + + + + +/*============================================================================== + Function Protoypes/MICROS +==============================================================================*/ +int vpx_get_size_of_pixel(unsigned int bd); +void *vpx_get_blitter(unsigned int bd); +void vpx_set_blit(void); +void vpx_destroy_blit(void); + + + +#endif //VPXBLIT_H_INCL
diff --git a/vp8/common/vpxblit_c64.h b/vp8/common/vpxblit_c64.h new file mode 100644 index 0000000..a8e28f5 --- /dev/null +++ b/vp8/common/vpxblit_c64.h
@@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _VPX_BLIT_C64_h +#define _VPX_BLIT_C64_h + +/**************************************************************************** +* Typedefs +****************************************************************************/ + +typedef struct // YUV buffer configuration structure +{ + int y_width; + int y_height; + int y_stride; + + int uv_width; + int uv_height; + int uv_stride; + + unsigned char *y_buffer; + unsigned char *u_buffer; + unsigned char *v_buffer; + + unsigned char *y_ptr_scrn; + unsigned char *u_ptr_scrn; + unsigned char *v_ptr_scrn; + +} DXV_YUV_BUFFER_CONFIG; + +typedef struct +{ + unsigned char *rgbptr_scrn; + unsigned char *y_ptr_scrn; + unsigned char *u_ptr_scrn; + unsigned char *v_ptr_scrn; + unsigned char *rgbptr_scrn2; +} DXV_FINAL_VIDEO; + +#endif /* include guards */
diff --git a/vp8/common/vpxerrors.h b/vp8/common/vpxerrors.h new file mode 100644 index 0000000..e4c9f3e --- /dev/null +++ b/vp8/common/vpxerrors.h
@@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + + +#define ALLOC_FAILURE -2
diff --git a/vp8/common/x86/boolcoder.cxx b/vp8/common/x86/boolcoder.cxx new file mode 100644 index 0000000..06faca6 --- /dev/null +++ b/vp8/common/x86/boolcoder.cxx
@@ -0,0 +1,493 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + + +/* Arithmetic bool coder with largish probability range. + Timothy S Murphy 6 August 2004 */ + +#include <assert.h> +#include <math.h> + +#include "bool_coder.h" + +#if tim_vp8 + extern "C" { +# include "VP8cx/treewriter.h" + } +#endif + +int_types::~int_types() {} + +void bool_coder_spec::check_prec() const { + assert( w && (r==Up || w > 1) && w < 24 && (ebias || w < 17)); +} + +bool bool_coder_spec::float_init( uint Ebits, uint Mbits) { + uint b = (ebits = Ebits) + (mbits = Mbits); + if( b) { + assert( ebits < 6 && w + mbits < 31); + assert( ebits + mbits < sizeof(Index) * 8); + ebias = (1 << ebits) + 1 + mbits; + mmask = (1 << mbits) - 1; + max_index = ( ( half_index = 1 << b ) << 1) - 1; + } else { + ebias = 0; + max_index = 255; + half_index = 128; + } + check_prec(); + return b? 1:0; +} + +void bool_coder_spec::cost_init() +{ + static cdouble c = -(1 << 20)/log( 2.); + + FILE *f = fopen( "costs.txt", "w"); + assert( f); + + assert( sizeof(int) >= 4); /* for C interface */ + assert( max_index <= 255); /* size of Ctbl */ + uint i = 0; do { + cdouble p = ( *this)( (Index) i); + Ctbl[i] = (uint32) ( log( p) * c); + fprintf( + f, "cost( %d -> %10.7f) = %10d = %12.5f bits\n", + i, p, Ctbl[i], (double) Ctbl[i] / (1<<20) + ); + } while( ++i <= max_index); + fclose( f); +} + +bool_coder_spec_explicit_table::bool_coder_spec_explicit_table( + cuint16 tbl[256], Rounding rr, uint prec +) + : bool_coder_spec( prec, rr) +{ + check_prec(); + uint i = 0; + if( tbl) + do { Ptbl[i] = tbl[i];} while( ++i < 256); + else + do { Ptbl[i] = i << 8;} while( ++i < 256); + cost_init(); +} + + +bool_coder_spec_exponential_table::bool_coder_spec_exponential_table( + uint x, Rounding rr, uint prec +) + : bool_coder_spec( prec, rr) +{ + assert( x > 1 && x <= 16); + check_prec(); + Ptbl[128] = 32768u; + Ptbl[0] = (uint16) pow( 2., 16. - x); + --x; + int i=1; do { + cdouble d = pow( .5, 1. + (1. - i/128.)*x) * 65536.; + uint16 v = (uint16) d; + if( v < i) + v = i; + Ptbl[256-i] = (uint16) ( 65536U - (Ptbl[i] = v)); + } while( ++i < 128); + cost_init(); +} + +bool_coder_spec::bool_coder_spec( FILE *fp) { + fscanf( fp, "%d", &w); + int v; + fscanf( fp, "%d", &v); + assert( 0 <= v && v <= 2); + r = (Rounding) v; + fscanf( fp, "%d", &ebits); + fscanf( fp, "%d", &mbits); + if( float_init( ebits, mbits)) + return; + int i=0; do { + uint v; + fscanf( fp, "%d", &v); + assert( 0 <=v && v <= 65535U); + Ptbl[i] = v; + } while( ++i < 256); + cost_init(); +} + +void bool_coder_spec::dump( FILE *fp) const { + fprintf( fp, "%d %d %d %d\n", w, (int) r, ebits, mbits); + if( ebits || mbits) + return; + int i=0; do { fprintf( fp, "%d\n", Ptbl[i]);} while( ++i < 256); +} + +vp8bc_index_t bool_coder_spec::operator()( double p) const +{ + if( p <= 0.) + return 0; + if( p >= 1.) + return max_index; + if( ebias) { + if( p > .5) + return max_index - ( *this)( 1. - p); + int e; + uint m = (uint) ldexp( frexp( p, &e), mbits + 2); + uint x = 1 << (mbits + 1); + assert( x <= m && m < x<<1); + if( (m = (m >> 1) + (m & 1)) >= x) { + m = x >> 1; + ++e; + } + int y = 1 << ebits; + if( (e += y) >= y) + return half_index - 1; + if( e < 0) + return 0; + return (Index) ( (e << mbits) + (m & mmask)); + } + + cuint16 v = (uint16) (p * 65536.); + int i = 128; + int j = 128; + uint16 w; + while( w = Ptbl[i], j >>= 1) { + if( w < v) + i += j; + else if( w == v) + return (uchar) i; + else + i -= j; + } + if( w > v) { + cuint16 x = Ptbl[i-1]; + if( v <= x || w - v > v - x) + --i; + } else if( w < v && i < 255) { + cuint16 x = Ptbl[i+1]; + if( x <= v || x - v < v - w) + ++i; + } + return (Index) i; +} + +double bool_coder_spec::operator()( Index i) const { + if( !ebias) + return Ptbl[i]/65536.; + if( i >= half_index) + return 1. - ( *this)( (Index) (max_index - i)); + return ldexp( (double)mantissa( i), - (int) exponent( i)); +} + + + +void bool_writer::carry() { + uchar *p = B; + assert( p > Bstart); + while( *--p == 255) { assert( p > Bstart); *p = 0;} + ++*p; +} + + +bool_writer::bool_writer( c_spec& s, uchar *Dest, size_t Len) + : bool_coder( s), + Bstart( Dest), + Bend( Len? Dest+Len : 0), + B( Dest) +{ + assert( Dest); + reset(); +} + +bool_writer::~bool_writer() { flush();} + +#if 1 + extern "C" { int bc_v = 0;} +#else +# define bc_v 0 +#endif + + +void bool_writer::raw( bool value, uint32 s) { + uint32 L = Low; + + assert( Range >= min_range && Range <= spec.max_range()); + assert( !is_toast && s && s < Range); + + if( bc_v) printf( + "Writing a %d, B %x Low %x Range %x s %x blag %d ...\n", + value? 1:0, B-Bstart, Low, Range, s, bit_lag + ); + if( value) { + L += s; + s = Range - s; + } else + s -= rinc; + if( s < min_range) { + int ct = bit_lag; do { + if( !--ct) { + ct = 8; + if( L & (1 << 31)) + carry(); + assert( !Bend || B < Bend); + *B++ = (uchar) (L >> 23); + L &= (1<<23) - 1; + } + } while( L += L, (s += s + rinc) < min_range); + bit_lag = ct; + } + Low = L; + Range = s; + if( bc_v) + printf( + "...done, B %x Low %x Range %x blag %d \n", + B-Bstart, Low, Range, bit_lag + ); +} + +bool_writer& bool_writer::flush() { + if( is_toast) + return *this; + int b = bit_lag; + uint32 L = Low; + assert( b); + if( L & (1 << (32 - b))) + carry(); + L <<= b & 7; + b >>= 3; + while( --b >= 0) + L <<= 8; + b = 4; + assert( !Bend || B + 4 <= Bend); + do { + *B++ = (uchar) (L >> 24); + L <<= 8; + } while( --b); + is_toast = 1; + return *this; +} + + +bool_reader::bool_reader( c_spec& s, cuchar *src, size_t Len) + : bool_coder( s), + Bstart( src), + B( src), + Bend( Len? src+Len : 0), + shf( 32 - s.w), + bct( 8) +{ + int i = 4; do { Low <<= 8; Low |= *B++;} while( --i); +} + + +bool bool_reader::raw( uint32 s) { + + bool val = 0; + uint32 L = Low; + cuint32 S = s << shf; + + assert( Range >= min_range && Range <= spec.max_range()); + assert( s && s < Range && (L >> shf) < Range); + + if( bc_v) + printf( + "Reading, B %x Low %x Range %x s %x bct %d ...\n", + B-Bstart, Low, Range, s, bct + ); + + if( L >= S) { + L -= S; + s = Range - s; + assert( L < (s << shf)); + val = 1; + } else + s -= rinc; + if( s < min_range) { + int ct = bct; + do { + assert( ~L & (1 << 31)); + L += L; + if( !--ct) { + ct = 8; + if( !Bend || B < Bend) + L |= *B++; + } + } while( (s += s + rinc) < min_range); + bct = ct; + } + Low = L; + Range = s; + if( bc_v) + printf( + "...done, val %d B %x Low %x Range %x bct %d\n", + val? 1:0, B-Bstart, Low, Range, bct + ); + return val; +} + + +/* C interfaces */ + +// spec interface + +struct NS : bool_coder_namespace { + static Rounding r( vp8bc_c_prec *p, Rounding rr =down_full) { + return p? (Rounding) p->r : rr; + } +}; + +bool_coder_spec *vp8bc_vp6spec() { + return new bool_coder_spec_explicit_table( 0, bool_coder_namespace::Down, 8); +} +bool_coder_spec *vp8bc_float_spec( + unsigned int Ebits, unsigned int Mbits, vp8bc_c_prec *p +) { + return new bool_coder_spec_float( Ebits, Mbits, NS::r( p), p? p->prec : 12); +} +bool_coder_spec *vp8bc_literal_spec( + const unsigned short m[256], vp8bc_c_prec *p +) { + return new bool_coder_spec_explicit_table( m, NS::r( p), p? p->prec : 16); +} +bool_coder_spec *vp8bc_exponential_spec( unsigned int x, vp8bc_c_prec *p) +{ + return new bool_coder_spec_exponential_table( x, NS::r( p), p? p->prec : 16); +} +bool_coder_spec *vp8bc_spec_from_file( FILE *fp) { + return new bool_coder_spec( fp); +} +void vp8bc_destroy_spec( c_bool_coder_spec *p) { delete p;} + +void vp8bc_spec_to_file( c_bool_coder_spec *p, FILE *fp) { p->dump( fp);} + +vp8bc_index_t vp8bc_index( c_bool_coder_spec *p, double x) { + return ( *p)( x); +} + +vp8bc_index_t vp8bc_index_from_counts( + c_bool_coder_spec *p, unsigned int L, unsigned int R +) { + return ( *p)( (R += L)? (double) L/R : .5); +} + +double vp8bc_probability( c_bool_coder_spec *p, vp8bc_index_t i) { + return ( *p)( i); +} + +vp8bc_index_t vp8bc_complement( c_bool_coder_spec *p, vp8bc_index_t i) { + return p->complement( i); +} +unsigned int vp8bc_cost_zero( c_bool_coder_spec *p, vp8bc_index_t i) { + return p->cost_zero( i); +} +unsigned int vp8bc_cost_one( c_bool_coder_spec *p, vp8bc_index_t i) { + return p->cost_one( i); +} +unsigned int vp8bc_cost_bit( c_bool_coder_spec *p, vp8bc_index_t i, int v) { + return p->cost_bit( i, v); +} + +#if tim_vp8 + extern "C" int tok_verbose; + +# define dbg_l 1000000 + + static vp8bc_index_t dbg_i [dbg_l]; + static char dbg_v [dbg_l]; + static size_t dbg_w = 0, dbg_r = 0; +#endif + +// writer interface + +bool_writer *vp8bc_create_writer( + c_bool_coder_spec *p, unsigned char *D, size_t L +) { + return new bool_writer( *p, D, L); +} + +size_t vp8bc_destroy_writer( bool_writer *p) { + const size_t s = p->flush().bytes_written(); + delete p; + return s; +} + +void vp8bc_write_bool( bool_writer *p, int v, vp8bc_index_t i) +{ +# if tim_vp8 + // bc_v = dbg_w < 10; + if( bc_v = tok_verbose) + printf( " writing %d at prob %d\n", v? 1:0, i); + accum_entropy_bc( &p->Spec(), i, v); + + ( *p)( i, (bool) v); + + if( dbg_w < dbg_l) { + dbg_i [dbg_w] = i; + dbg_v [dbg_w++] = v? 1:0; + } +# else + ( *p)( i, (bool) v); +# endif +} + +void vp8bc_write_bits( bool_writer *p, unsigned int v, int n) +{ +# if tim_vp8 + { + c_bool_coder_spec * const s = & p->Spec(); + const vp8bc_index_t i = s->half_index(); + int m = n; + while( --m >= 0) + accum_entropy_bc( s, i, (v>>m) & 1); + } +# endif + + p->write_bits( n, v); +} + +c_bool_coder_spec *vp8bc_writer_spec( c_bool_writer *w) { return & w->Spec();} + +// reader interface + +bool_reader *vp8bc_create_reader( + c_bool_coder_spec *p, const unsigned char *S, size_t L +) { + return new bool_reader( *p, S, L); +} + +void vp8bc_destroy_reader( bool_reader * p) { delete p;} + +int vp8bc_read_bool( bool_reader *p, vp8bc_index_t i) +{ +# if tim_vp8 + // bc_v = dbg_r < 10; + bc_v = tok_verbose; + const int v = ( *p)( i)? 1:0; + if( tok_verbose) + printf( " reading %d at prob %d\n", v, i); + if( dbg_r < dbg_l) { + assert( dbg_r <= dbg_w); + if( i != dbg_i[dbg_r] || v != dbg_v[dbg_r]) { + printf( + "Position %d: INCORRECTLY READING %d prob %d, wrote %d prob %d\n", + dbg_r, v, i, dbg_v[dbg_r], dbg_i[dbg_r] + ); + } + ++dbg_r; + } + return v; +# else + return ( *p)( i)? 1:0; +# endif +} + +unsigned int vp8bc_read_bits( bool_reader *p, int n) { return p->read_bits( n);} + +c_bool_coder_spec *vp8bc_reader_spec( c_bool_reader *r) { return & r->Spec();} + +#undef bc_v
diff --git a/vp8/common/x86/idct_x86.h b/vp8/common/x86/idct_x86.h new file mode 100644 index 0000000..5dfb212 --- /dev/null +++ b/vp8/common/x86/idct_x86.h
@@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef IDCT_X86_H +#define IDCT_X86_H + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ + +#if HAVE_MMX +extern prototype_idct(vp8_short_idct4x4llm_1_mmx); +extern prototype_idct(vp8_short_idct4x4llm_mmx); +extern prototype_idct_scalar(vp8_dc_only_idct_mmx); + +extern prototype_second_order(vp8_short_inv_walsh4x4_mmx); +extern prototype_second_order(vp8_short_inv_walsh4x4_1_mmx); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_idct_idct1 +#define vp8_idct_idct1 vp8_short_idct4x4llm_1_mmx + +#undef vp8_idct_idct16 +#define vp8_idct_idct16 vp8_short_idct4x4llm_mmx + +#undef vp8_idct_idct1_scalar +#define vp8_idct_idct1_scalar vp8_dc_only_idct_mmx + +#undef vp8_idct_iwalsh16 +#define vp8_idct_iwalsh16 vp8_short_inv_walsh4x4_mmx + +#undef vp8_idct_iwalsh1 +#define vp8_idct_iwalsh1 vp8_short_inv_walsh4x4_1_mmx + +#endif +#endif + +#if HAVE_SSE2 + +extern prototype_second_order(vp8_short_inv_walsh4x4_sse2); + +#if !CONFIG_RUNTIME_CPU_DETECT + +#undef vp8_idct_iwalsh16 +#define vp8_idct_iwalsh16 vp8_short_inv_walsh4x4_sse2 + +#endif + +#endif + + + +#endif
diff --git a/vp8/common/x86/idctllm_mmx.asm b/vp8/common/x86/idctllm_mmx.asm new file mode 100644 index 0000000..2751c69 --- /dev/null +++ b/vp8/common/x86/idctllm_mmx.asm
@@ -0,0 +1,265 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +; /**************************************************************************** +; * Notes: +; * +; * This implementation makes use of 16 bit fixed point verio of two multiply +; * constants: +; * 1. sqrt(2) * cos (pi/8) +; * 2. sqrt(2) * sin (pi/8) +; * Becuase the first constant is bigger than 1, to maintain the same 16 bit +; * fixed point prrcision as the second one, we use a trick of +; * x * a = x + x*(a-1) +; * so +; * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). +; * +; * For the second constant, becuase of the 16bit version is 35468, which +; * is bigger than 32768, in signed 16 bit multiply, it become a negative +; * number. +; * (x * (unsigned)35468 >> 16) = x * (signed)35468 >> 16 + x +; * +; **************************************************************************/ + + +;void short_idct4x4llm_mmx(short *input, short *output, int pitch) +global sym(vp8_short_idct4x4llm_mmx) +sym(vp8_short_idct4x4llm_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + ; end prolog + + mov rax, arg(0) ;input + mov rdx, arg(1) ;output + + movq mm0, [rax ] + movq mm1, [rax+ 8] + + movq mm2, [rax+16] + movq mm3, [rax+24] + + movsxd rax, dword ptr arg(2) ;pitch + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL] ; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL] ; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq mm3, mm5 ; 33 23 13 03 + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL] ; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL] ; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + paddw mm0, [fours GLOBAL] + + paddw mm2, [fours GLOBAL] + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + psraw mm2, 3 + + psraw mm0, 3 + psraw mm4, 3 + + psraw mm6, 3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq [rdx], mm0 + + movq [rdx+rax], mm1 + movq [rdx+rax*2], mm2 + + add rdx, rax + movq [rdx+rax*2], mm5 + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void short_idct4x4llm_1_mmx(short *input, short *output, int pitch) +global sym(vp8_short_idct4x4llm_1_mmx) +sym(vp8_short_idct4x4llm_1_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + ; end prolog + + mov rax, arg(0) ;input + movd mm0, [rax] + + paddw mm0, [fours GLOBAL] + mov rdx, arg(1) ;output + + psraw mm0, 3 + movsxd rax, dword ptr arg(2) ;pitch + + punpcklwd mm0, mm0 + punpckldq mm0, mm0 + + movq [rdx], mm0 + movq [rdx+rax], mm0 + + movq [rdx+rax*2], mm0 + add rdx, rax + + movq [rdx+rax*2], mm0 + + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void dc_only_idct_mmx(short input_dc, short *output, int pitch) +global sym(vp8_dc_only_idct_mmx) +sym(vp8_dc_only_idct_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + ; end prolog + + movd mm0, arg(0) ;input_dc + + paddw mm0, [fours GLOBAL] + mov rdx, arg(1) ;output + + psraw mm0, 3 + movsxd rax, dword ptr arg(2) ;pitch + + punpcklwd mm0, mm0 + punpckldq mm0, mm0 + + movq [rdx], mm0 + movq [rdx+rax], mm0 + + movq [rdx+rax*2], mm0 + add rdx, rax + + movq [rdx+rax*2], mm0 + + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +x_s1sqr2: + times 4 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 4 dw 0x4E7B +align 16 +fours: + times 4 dw 0x0004
diff --git a/vp8/common/x86/iwalsh_mmx.asm b/vp8/common/x86/iwalsh_mmx.asm new file mode 100644 index 0000000..562e590 --- /dev/null +++ b/vp8/common/x86/iwalsh_mmx.asm
@@ -0,0 +1,172 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_inv_walsh4x4_1_mmx(short *input, short *output) +global sym(vp8_short_inv_walsh4x4_1_mmx) +sym(vp8_short_inv_walsh4x4_1_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) + mov rax, 3 + + mov rdi, arg(1) + add rax, [rsi] ;input[0] + 3 + + movd mm0, eax + + punpcklwd mm0, mm0 ;x x val val + + punpckldq mm0, mm0 ;val val val val + + psraw mm0, 3 ;(input[0] + 3) >> 3 + + movq [rdi + 0], mm0 + movq [rdi + 8], mm0 + movq [rdi + 16], mm0 + movq [rdi + 24], mm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_short_inv_walsh4x4_mmx(short *input, short *output) +global sym(vp8_short_inv_walsh4x4_mmx) +sym(vp8_short_inv_walsh4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + mov rax, 3 + mov rsi, arg(0) + mov rdi, arg(1) + shl rax, 16 + + movq mm0, [rsi + 0] ;ip[0] + movq mm1, [rsi + 8] ;ip[4] + or rax, 3 ;00030003h + + movq mm2, [rsi + 16] ;ip[8] + movq mm3, [rsi + 24] ;ip[12] + + movd mm7, rax + movq mm4, mm0 + + punpcklwd mm7, mm7 ;0003000300030003h + movq mm5, mm1 + + paddw mm4, mm3 ;ip[0] + ip[12] aka al + paddw mm5, mm2 ;ip[4] + ip[8] aka bl + + movq mm6, mm4 ;temp al + + paddw mm4, mm5 ;al + bl + psubw mm6, mm5 ;al - bl + + psubw mm0, mm3 ;ip[0] - ip[12] aka d1 + psubw mm1, mm2 ;ip[4] - ip[8] aka c1 + + movq mm5, mm0 ;temp dl + + paddw mm0, mm1 ;dl + cl + psubw mm5, mm1 ;dl - cl + + ; 03 02 01 00 + ; 13 12 11 10 + ; 23 22 21 20 + ; 33 32 31 30 + + movq mm3, mm4 ; 03 02 01 00 + punpcklwd mm4, mm0 ; 11 01 10 00 + punpckhwd mm3, mm0 ; 13 03 12 02 + + movq mm1, mm6 ; 23 22 21 20 + punpcklwd mm6, mm5 ; 31 21 30 20 + punpckhwd mm1, mm5 ; 33 23 32 22 + + movq mm0, mm4 ; 11 01 10 00 + movq mm2, mm3 ; 13 03 12 02 + + punpckldq mm0, mm6 ; 30 20 10 00 aka ip[0] + punpckhdq mm4, mm6 ; 31 21 11 01 aka ip[4] + + punpckldq mm2, mm1 ; 32 22 12 02 aka ip[8] + punpckhdq mm3, mm1 ; 33 23 13 03 aka ip[12] +;~~~~~~~~~~~~~~~~~~~~~ + movq mm1, mm0 + movq mm5, mm4 + + paddw mm1, mm3 ;ip[0] + ip[12] aka al + paddw mm5, mm2 ;ip[4] + ip[8] aka bl + + movq mm6, mm1 ;temp al + + paddw mm1, mm5 ;al + bl + psubw mm6, mm5 ;al - bl + + psubw mm0, mm3 ;ip[0] - ip[12] aka d1 + psubw mm4, mm2 ;ip[4] - ip[8] aka c1 + + movq mm5, mm0 ;temp dl + + paddw mm0, mm4 ;dl + cl + psubw mm5, mm4 ;dl - cl +;~~~~~~~~~~~~~~~~~~~~~ + movq mm3, mm1 ; 03 02 01 00 + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm3, mm0 ; 13 03 12 02 + + movq mm4, mm6 ; 23 22 21 20 + punpcklwd mm6, mm5 ; 31 21 30 20 + punpckhwd mm4, mm5 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm2, mm3 ; 13 03 12 02 + + punpckldq mm0, mm6 ; 30 20 10 00 aka ip[0] + punpckhdq mm1, mm6 ; 31 21 11 01 aka ip[4] + + punpckldq mm2, mm4 ; 32 22 12 02 aka ip[8] + punpckhdq mm3, mm4 ; 33 23 13 03 aka ip[12] + + paddw mm0, mm7 + paddw mm1, mm7 + paddw mm2, mm7 + paddw mm3, mm7 + + psraw mm0, 3 + psraw mm1, 3 + psraw mm2, 3 + psraw mm3, 3 + + movq [rdi + 0], mm0 + movq [rdi + 8], mm1 + movq [rdi + 16], mm2 + movq [rdi + 24], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret +
diff --git a/vp8/common/x86/iwalsh_sse2.asm b/vp8/common/x86/iwalsh_sse2.asm new file mode 100644 index 0000000..96943df --- /dev/null +++ b/vp8/common/x86/iwalsh_sse2.asm
@@ -0,0 +1,116 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_inv_walsh4x4_sse2(short *input, short *output) +global sym(vp8_short_inv_walsh4x4_sse2) +sym(vp8_short_inv_walsh4x4_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) + mov rdi, arg(1) + mov rax, 3 + + movdqa xmm0, [rsi + 0] ;ip[4] ip[0] + movdqa xmm1, [rsi + 16] ;ip[12] ip[8] + + shl rax, 16 + or rax, 3 ;00030003h + + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm0 ;ip[4] ip[0] + + paddw xmm0, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm4, xmm0 + punpcklqdq xmm0, xmm3 ;d1 a1 + punpckhqdq xmm4, xmm3 ;c1 b1 + movd xmm7, eax + + movdqa xmm1, xmm4 ;c1 b1 + paddw xmm4, xmm0 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm0, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] + +;;;temp output +;; movdqu [rdi + 0], xmm4 +;; movdqu [rdi + 16], xmm3 + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; 13 12 11 10 03 02 01 00 + ; + ; 33 32 31 30 23 22 21 20 + ; + movdqa xmm3, xmm4 ; 13 12 11 10 03 02 01 00 + punpcklwd xmm4, xmm0 ; 23 03 22 02 21 01 20 00 + punpckhwd xmm3, xmm0 ; 33 13 32 12 31 11 30 10 + movdqa xmm1, xmm4 ; 23 03 22 02 21 01 20 00 + punpcklwd xmm4, xmm3 ; 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm3 ; 33 23 13 03 32 22 12 02 + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm4 ;ip[4] ip[0] + + pshufd xmm7, xmm7, 0 ;03 03 03 03 03 03 03 03 + + paddw xmm4, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm3 ;d1 a1 + punpckhqdq xmm5, xmm3 ;c1 b1 + + movdqa xmm1, xmm5 ;c1 b1 + paddw xmm5, xmm4 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm4, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; 13 12 11 10 03 02 01 00 + ; + ; 33 32 31 30 23 22 21 20 + ; + movdqa xmm0, xmm5 ; 13 12 11 10 03 02 01 00 + punpcklwd xmm5, xmm4 ; 23 03 22 02 21 01 20 00 + punpckhwd xmm0, xmm4 ; 33 13 32 12 31 11 30 10 + movdqa xmm1, xmm5 ; 23 03 22 02 21 01 20 00 + punpcklwd xmm5, xmm0 ; 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm0 ; 33 23 13 03 32 22 12 02 +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + paddw xmm5, xmm7 + paddw xmm1, xmm7 + + psraw xmm5, 3 + psraw xmm1, 3 + + movdqa [rdi + 0], xmm5 + movdqa [rdi + 16], xmm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +x_s1sqr2: + times 4 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 4 dw 0x4E7B +align 16 +fours: + times 4 dw 0x0004
diff --git a/vp8/common/x86/loopfilter_mmx.asm b/vp8/common/x86/loopfilter_mmx.asm new file mode 100644 index 0000000..6e4d2b6 --- /dev/null +++ b/vp8/common/x86/loopfilter_mmx.asm
@@ -0,0 +1,1776 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void vp8_loop_filter_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_horizontal_edge_mmx) +sym(vp8_loop_filter_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + movsxd rcx, dword ptr arg(5) ;count +next8_h: + mov rdx, arg(3) ;limit + movq mm7, [rdx] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movq mm2, [rdi+2*rax] ; q3 + movq mm1, [rsi+2*rax] ; q2 + movq mm6, mm1 ; q2 + psubusb mm1, mm2 ; q2-=q3 + psubusb mm2, mm6 ; q3-=q2 + por mm1, mm2 ; abs(q3-q2) + psubusb mm1, mm7 ; + + + movq mm4, [rsi+rax] ; q1 + movq mm3, mm4 ; q1 + psubusb mm4, mm6 ; q1-=q2 + psubusb mm6, mm3 ; q2-=q1 + por mm4, mm6 ; abs(q2-q1) + + psubusb mm4, mm7 + por mm1, mm4 + + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + psubusb mm4, mm3 ; q0-=q1 + psubusb mm3, mm0 ; q1-=q0 + por mm4, mm3 ; abs(q0-q1) + movq t0, mm4 ; save to t0 + psubusb mm4, mm7 + por mm1, mm4 + + + neg rax ; negate pitch to deal with above border + + movq mm2, [rsi+4*rax] ; p3 + movq mm4, [rdi+4*rax] ; p2 + movq mm5, mm4 ; p2 + psubusb mm4, mm2 ; p2-=p3 + psubusb mm2, mm5 ; p3-=p2 + por mm4, mm2 ; abs(p3 - p2) + psubusb mm4, mm7 + por mm1, mm4 + + + movq mm4, [rsi+2*rax] ; p1 + movq mm3, mm4 ; p1 + psubusb mm4, mm5 ; p1-=p2 + psubusb mm5, mm3 ; p2-=p1 + por mm4, mm5 ; abs(p2 - p1) + psubusb mm4, mm7 + por mm1, mm4 + + movq mm2, mm3 ; p1 + + movq mm4, [rsi+rax] ; p0 + movq mm5, mm4 ; p0 + psubusb mm4, mm3 ; p0-=p1 + psubusb mm3, mm5 ; p1-=p0 + por mm4, mm3 ; abs(p1 - p0) + movq t1, mm4 ; save to t1 + psubusb mm4, mm7 + por mm1, mm4 + + movq mm3, [rdi] ; q1 + movq mm4, mm3 ; q1 + psubusb mm3, mm2 ; q1-=p1 + psubusb mm2, mm4 ; p1-=q1 + por mm2, mm3 ; abs(p1-q1) + pand mm2, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm2, 1 ; abs(p1-q1)/2 + + movq mm6, mm5 ; p0 + movq mm3, [rsi] ; q0 + psubusb mm5, mm3 ; p0-=q0 + psubusb mm3, mm6 ; q0-=p0 + por mm5, mm3 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; get flimit + movq mm2, [rdx] ; flimit mm2 + paddb mm2, mm2 ; flimit*2 (less than 255) + paddb mm7, mm2 ; flimit * 2 + limit (less than 255) + + psubusb mm5, mm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por mm1, mm5 + pxor mm5, mm5 + pcmpeqb mm1, mm5 ; mask mm1 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + paddb mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + pcmpeqb mm4, mm5 + + pcmpeqb mm5, mm5 + pxor mm4, mm5 + + + ; start work on filters + movq mm2, [rsi+2*rax] ; p1 + movq mm7, [rdi] ; q1 + pxor mm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + pand mm2, mm4 ; high var mask (hvm)(p1 - q1) + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + pxor mm0, [t80 GLOBAL] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + movq mm2, mm1 + paddsb mm1, [t4 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + paddsb mm2, [t3 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + + pxor mm0, mm0 ; + pxor mm5, mm5 + punpcklbw mm0, mm2 ; + punpckhbw mm5, mm2 ; + psraw mm0, 11 ; + psraw mm5, 11 + packsswb mm0, mm5 + movq mm2, mm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor mm0, mm0 ; 0 + movq mm5, mm1 ; abcdefgh + punpcklbw mm0, mm1 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + pxor mm1, mm1 ; 0 + punpckhbw mm1, mm5 ; a0b0c0d0 + psraw mm1, 11 ; sign extended shift right by 3 + movq mm5, mm0 ; save results + + packsswb mm0, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw mm5, [ones GLOBAL] + paddsw mm1, [ones GLOBAL] + psraw mm5, 1 ; partial shifted one more time for 2nd tap + psraw mm1, 1 ; partial shifted one more time for 2nd tap + packsswb mm5, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + pandn mm4, mm5 ; high edge variance additive + + paddsb mm6, mm2 ; p0+= p0 add + pxor mm6, [t80 GLOBAL] ; unoffset + movq [rsi+rax], mm6 ; write back + + movq mm6, [rsi+2*rax] ; p1 + pxor mm6, [t80 GLOBAL] ; reoffset + paddsb mm6, mm4 ; p1+= p1 add + pxor mm6, [t80 GLOBAL] ; unoffset + movq [rsi+2*rax], mm6 ; write back + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [t80 GLOBAL] ; unoffset + movq [rsi], mm3 ; write back + + psubsb mm7, mm4 ; q1-= q1 add + pxor mm7, [t80 GLOBAL] ; unoffset + movq [rdi], mm7 ; write back + + add rsi,8 + neg rax + dec rcx + jnz next8_h + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_vertical_edge_mmx) +sym(vp8_loop_filter_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 64 ; reserve 64 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[32]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + + movsxd rcx, dword ptr arg(5) ;count +next8_v: + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + + ;transpose + movq mm6, [rsi+2*rax] ; 67 66 65 64 63 62 61 60 + movq mm7, mm6 ; 77 76 75 74 73 72 71 70 + + punpckhbw mm7, [rdi+2*rax] ; 77 67 76 66 75 65 74 64 + punpcklbw mm6, [rdi+2*rax] ; 73 63 72 62 71 61 70 60 + + movq mm4, [rsi] ; 47 46 45 44 43 42 41 40 + movq mm5, mm4 ; 47 46 45 44 43 42 41 40 + + punpckhbw mm5, [rsi+rax] ; 57 47 56 46 55 45 54 44 + punpcklbw mm4, [rsi+rax] ; 53 43 52 42 51 41 50 40 + + movq mm3, mm5 ; 57 47 56 46 55 45 54 44 + punpckhwd mm5, mm7 ; 77 67 57 47 76 66 56 46 + + punpcklwd mm3, mm7 ; 75 65 55 45 74 64 54 44 + movq mm2, mm4 ; 53 43 52 42 51 41 50 40 + + punpckhwd mm4, mm6 ; 73 63 53 43 72 62 52 42 + punpcklwd mm2, mm6 ; 71 61 51 41 70 60 50 40 + + neg rax + movq mm6, [rsi+rax*2] ; 27 26 25 24 23 22 21 20 + + movq mm1, mm6 ; 27 26 25 24 23 22 21 20 + punpckhbw mm6, [rsi+rax] ; 37 27 36 36 35 25 34 24 + + punpcklbw mm1, [rsi+rax] ; 33 23 32 22 31 21 30 20 + movq mm7, [rsi+rax*4]; ; 07 06 05 04 03 02 01 00 + + punpckhbw mm7, [rdi+rax*4] ; 17 07 16 06 15 05 14 04 + movq mm0, mm7 ; 17 07 16 06 15 05 14 04 + + punpckhwd mm7, mm6 ; 37 27 17 07 36 26 16 06 + punpcklwd mm0, mm6 ; 35 25 15 05 34 24 14 04 + + movq mm6, mm7 ; 37 27 17 07 36 26 16 06 + punpckhdq mm7, mm5 ; 77 67 57 47 37 27 17 07 = q3 + + punpckldq mm6, mm5 ; 76 66 56 46 36 26 16 06 = q2 + + movq mm5, mm6 ; 76 66 56 46 36 26 16 06 + psubusb mm5, mm7 ; q2-q3 + + psubusb mm7, mm6 ; q3-q2 + por mm7, mm5; ; mm7=abs (q3-q2) + + movq mm5, mm0 ; 35 25 15 05 34 24 14 04 + punpckhdq mm5, mm3 ; 75 65 55 45 35 25 15 05 = q1 + + punpckldq mm0, mm3 ; 74 64 54 44 34 24 15 04 = q0 + movq mm3, mm5 ; 75 65 55 45 35 25 15 05 = q1 + + psubusb mm3, mm6 ; q1-q2 + psubusb mm6, mm5 ; q2-q1 + + por mm6, mm3 ; mm6=abs(q2-q1) + lea rdx, srct + + movq [rdx+24], mm5 ; save q1 + movq [rdx+16], mm0 ; save q0 + + movq mm3, [rsi+rax*4] ; 07 06 05 04 03 02 01 00 + punpcklbw mm3, [rdi+rax*4] ; 13 03 12 02 11 01 10 00 + + movq mm0, mm3 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm1 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm3, mm1 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 31 21 11 01 30 20 10 00 + + punpckldq mm0, mm2 ; 70 60 50 40 30 20 10 00 =p3 + punpckhdq mm1, mm2 ; 71 61 51 41 31 21 11 01 =p2 + + movq mm2, mm1 ; 71 61 51 41 31 21 11 01 =p2 + psubusb mm2, mm0 ; p2-p3 + + psubusb mm0, mm1 ; p3-p2 + por mm0, mm2 ; mm0=abs(p3-p2) + + movq mm2, mm3 ; 33 23 13 03 32 22 12 02 + punpckldq mm2, mm4 ; 72 62 52 42 32 22 12 02 = p1 + + punpckhdq mm3, mm4 ; 73 63 53 43 33 23 13 03 = p0 + movq [rdx+8], mm3 ; save p0 + + movq [rdx], mm2 ; save p1 + movq mm5, mm2 ; mm5 = p1 + + psubusb mm2, mm1 ; p1-p2 + psubusb mm1, mm5 ; p2-p1 + + por mm1, mm2 ; mm1=abs(p2-p1) + mov rdx, arg(3) ;limit + + movq mm4, [rdx] ; mm4 = limit + psubusb mm7, mm4 + + psubusb mm0, mm4 + psubusb mm1, mm4 + + psubusb mm6, mm4 + por mm7, mm6 + + por mm0, mm1 + por mm0, mm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movq mm1, mm5 ; p1 + + movq mm7, mm3 ; mm3=mm7=p0 + psubusb mm7, mm5 ; p0 - p1 + + psubusb mm5, mm3 ; p1 - p0 + por mm5, mm7 ; abs(p1-p0) + + movq t0, mm5 ; save abs(p1-p0) + lea rdx, srct + + psubusb mm5, mm4 + por mm0, mm5 ; mm0=mask + + movq mm5, [rdx+16] ; mm5=q0 + movq mm7, [rdx+24] ; mm7=q1 + + movq mm6, mm5 ; mm6=q0 + movq mm2, mm7 ; q1 + psubusb mm5, mm7 ; q0-q1 + + psubusb mm7, mm6 ; q1-q0 + por mm7, mm5 ; abs(q1-q0) + + movq t1, mm7 ; save abs(q1-q0) + psubusb mm7, mm4 + + por mm0, mm7 ; mask + + movq mm5, mm2 ; q1 + psubusb mm5, mm1 ; q1-=p1 + psubusb mm1, mm2 ; p1-=q1 + por mm5, mm1 ; abs(p1-q1) + pand mm5, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; + + movq mm2, [rdx] ;flimit mm2 + movq mm1, mm3 ; mm1=mm3=p0 + + movq mm7, mm6 ; mm7=mm6=q0 + psubusb mm1, mm7 ; p0-q0 + + psubusb mm7, mm3 ; q0-p0 + por mm1, mm7 ; abs(q0-p0) + paddusb mm1, mm1 ; abs(q0-p0)*2 + paddusb mm1, mm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + paddb mm2, mm2 ; flimit*2 (less than 255) + paddb mm4, mm2 ; flimit * 2 + limit (less than 255) + + psubusb mm1, mm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por mm1, mm0; ; mask + + pxor mm0, mm0 + pcmpeqb mm1, mm0 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] + ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + + por mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb mm4, mm0 + + pcmpeqb mm0, mm0 + pxor mm4, mm0 + + + + ; start work on filters + lea rdx, srct + + movq mm2, [rdx] ; p1 + movq mm7, [rdx+24] ; q1 + + movq mm6, [rdx+8] ; p0 + movq mm0, [rdx+16] ; q0 + + pxor mm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm7, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb mm2, mm7 ; p1 - q1 + pand mm2, mm4 ; high var mask (hvm)(p1 - q1) + + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + pxor mm0, [t80 GLOBAL] ; offset to convert to signed values + + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + + paddsb mm2, mm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + + paddsb mm2, mm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + movq mm2, mm1 + paddsb mm1, [t4 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + + paddsb mm2, [t3 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + pxor mm0, mm0 ; + + pxor mm5, mm5 + punpcklbw mm0, mm2 ; + + punpckhbw mm5, mm2 ; + psraw mm0, 11 ; + + psraw mm5, 11 + packsswb mm0, mm5 + + movq mm2, mm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor mm0, mm0 ; 0 + movq mm5, mm1 ; abcdefgh + + punpcklbw mm0, mm1 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + + pxor mm1, mm1 ; 0 + punpckhbw mm1, mm5 ; a0b0c0d0 + + psraw mm1, 11 ; sign extended shift right by 3 + movq mm5, mm0 ; save results + + packsswb mm0, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw mm5, [ones GLOBAL] + + paddsw mm1, [ones GLOBAL] + psraw mm5, 1 ; partial shifted one more time for 2nd tap + + psraw mm1, 1 ; partial shifted one more time for 2nd tap + packsswb mm5, mm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + + pandn mm4, mm5 ; high edge variance additive + + paddsb mm6, mm2 ; p0+= p0 add + pxor mm6, [t80 GLOBAL] ; unoffset + + ; mm6=p0 ; + movq mm1, [rdx] ; p1 + pxor mm1, [t80 GLOBAL] ; reoffset + + paddsb mm1, mm4 ; p1+= p1 add + pxor mm1, [t80 GLOBAL] ; unoffset + ; mm6 = p0 mm1 = p1 + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [t80 GLOBAL] ; unoffset + + ; mm3 = q0 + psubsb mm7, mm4 ; q1-= q1 add + pxor mm7, [t80 GLOBAL] ; unoffset + ; mm7 = q1 + + ; tranpose and write back + ; mm1 = 72 62 52 42 32 22 12 02 + ; mm6 = 73 63 53 43 33 23 13 03 + ; mm3 = 74 64 54 44 34 24 14 04 + ; mm7 = 75 65 55 45 35 25 15 05 + + movq mm2, mm1 ; 72 62 52 42 32 22 12 02 + punpcklbw mm2, mm6 ; 33 32 23 22 13 12 03 02 + + movq mm4, mm3 ; 74 64 54 44 34 24 14 04 + punpckhbw mm1, mm6 ; 73 72 63 62 53 52 43 42 + + punpcklbw mm4, mm7 ; 35 34 25 24 15 14 05 04 + punpckhbw mm3, mm7 ; 75 74 65 64 55 54 45 44 + + movq mm6, mm2 ; 33 32 23 22 13 12 03 02 + punpcklwd mm2, mm4 ; 15 14 13 12 05 04 03 02 + + punpckhwd mm6, mm4 ; 35 34 33 32 25 24 23 22 + movq mm5, mm1 ; 73 72 63 62 53 52 43 42 + + punpcklwd mm1, mm3 ; 55 54 53 52 45 44 43 42 + punpckhwd mm5, mm3 ; 75 74 73 72 65 64 63 62 + + + ; mm2 = 15 14 13 12 05 04 03 02 + ; mm6 = 35 34 33 32 25 24 23 22 + ; mm5 = 55 54 53 52 45 44 43 42 + ; mm1 = 75 74 73 72 65 64 63 62 + + + + movd [rsi+rax*4+2], mm2 + psrlq mm2, 32 + + movd [rdi+rax*4+2], mm2 + movd [rsi+rax*2+2], mm6 + + psrlq mm6, 32 + movd [rsi+rax+2],mm6 + + movd [rsi+2], mm1 + psrlq mm1, 32 + + movd [rdi+2], mm1 + neg rax + + movd [rdi+rax+2],mm5 + psrlq mm5, 32 + + movd [rdi+rax*2+2], mm5 + + lea rsi, [rsi+rax*8] + dec rcx + jnz next8_v + + add rsp, 64 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_horizontal_edge_mmx) +sym(vp8_mbloop_filter_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + movsxd rcx, dword ptr arg(5) ;count +next8_mbh: + mov rdx, arg(3) ;limit + movq mm7, [rdx] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movq mm2, [rdi+2*rax] ; q3 + + movq mm1, [rsi+2*rax] ; q2 + movq mm6, mm1 ; q2 + psubusb mm1, mm2 ; q2-=q3 + psubusb mm2, mm6 ; q3-=q2 + por mm1, mm2 ; abs(q3-q2) + psubusb mm1, mm7 + + + ; mm1 = abs(q3-q2), mm6 =q2, mm7 = limit + movq mm4, [rsi+rax] ; q1 + movq mm3, mm4 ; q1 + psubusb mm4, mm6 ; q1-=q2 + psubusb mm6, mm3 ; q2-=q1 + por mm4, mm6 ; abs(q2-q1) + psubusb mm4, mm7 + por mm1, mm4 + + + ; mm1 = mask, mm3=q1, mm7 = limit + + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + psubusb mm4, mm3 ; q0-=q1 + psubusb mm3, mm0 ; q1-=q0 + por mm4, mm3 ; abs(q0-q1) + movq t0, mm4 ; save to t0 + psubusb mm4, mm7 + por mm1, mm4 + + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + neg rax ; negate pitch to deal with above border + + movq mm2, [rsi+4*rax] ; p3 + movq mm4, [rdi+4*rax] ; p2 + movq mm5, mm4 ; p2 + psubusb mm4, mm2 ; p2-=p3 + psubusb mm2, mm5 ; p3-=p2 + por mm4, mm2 ; abs(p3 - p2) + psubusb mm4, mm7 + por mm1, mm4 + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + movq mm4, [rsi+2*rax] ; p1 + movq mm3, mm4 ; p1 + psubusb mm4, mm5 ; p1-=p2 + psubusb mm5, mm3 ; p2-=p1 + por mm4, mm5 ; abs(p2 - p1) + psubusb mm4, mm7 + por mm1, mm4 + + movq mm2, mm3 ; p1 + + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + + movq mm4, [rsi+rax] ; p0 + movq mm5, mm4 ; p0 + psubusb mm4, mm3 ; p0-=p1 + psubusb mm3, mm5 ; p1-=p0 + por mm4, mm3 ; abs(p1 - p0) + movq t1, mm4 ; save to t1 + psubusb mm4, mm7 + por mm1, mm4 + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm5 = p0 + movq mm3, [rdi] ; q1 + movq mm4, mm3 ; q1 + psubusb mm3, mm2 ; q1-=p1 + psubusb mm2, mm4 ; p1-=q1 + por mm2, mm3 ; abs(p1-q1) + pand mm2, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm2, 1 ; abs(p1-q1)/2 + + movq mm6, mm5 ; p0 + movq mm3, mm0 ; q0 + psubusb mm5, mm3 ; p0-=q0 + psubusb mm3, mm6 ; q0-=p0 + por mm5, mm3 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; get flimit + movq mm2, [rdx] ; flimit mm2 + paddb mm2, mm2 ; flimit*2 (less than 255) + paddb mm7, mm2 ; flimit * 2 + limit (less than 255) + + psubusb mm5, mm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por mm1, mm5 + pxor mm5, mm5 + pcmpeqb mm1, mm5 ; mask mm1 + + ; mm1 = mask, mm0=q0, mm7 = flimit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 + paddb mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + + pcmpeqb mm4, mm5 + + pcmpeqb mm5, mm5 + pxor mm4, mm5 + + + + ; mm1 = mask, mm0=q0, mm7 = thresh, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, mm4=hev + ; start work on filters + movq mm2, [rsi+2*rax] ; p1 + movq mm7, [rdi] ; q1 + pxor mm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + pxor mm0, [t80 GLOBAL] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + (p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + paddsb mm2, mm0 ; 3 * (q0 - p0) + (p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + + ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0 + movq mm2, mm1 ; vp8_filter + pand mm2, mm4; ; Filter2 = vp8_filter & hev + + movq mm5, mm2 ; + paddsb mm5, [t3 GLOBAL]; + + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm5 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm5 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + movq mm5, mm0 ; Filter2 + + paddsb mm2, [t4 GLOBAL] ; vp8_signed_char_clamp(Filter2 + 4) + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm2 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm2 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + ; mm0= filter2 mm1 = vp8_filter, mm3 =qs0 mm5=s mm4 =hev mm6=ps0 + psubsb mm3, mm0 ; qs0 =qs0 - filter1 + paddsb mm6, mm5 ; ps0 =ps0 + Fitler2 + + ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn mm4, mm1 ; vp8_filter&=~hev + + + ; mm3=qs0, mm4=filter2, mm6=ps0 + + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor mm0, mm0 + + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s27 GLOBAL] + pmulhw mm2, [s27 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + psubsb mm3, mm1 + paddsb mm6, mm1 + + pxor mm3, [t80 GLOBAL] + pxor mm6, [t80 GLOBAL] + movq [rsi+rax], mm6 + movq [rsi], mm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s18 GLOBAL] + pmulhw mm2, [s18 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm3, [rdi] + movq mm6, [rsi+rax*2] ; p1 + + pxor mm3, [t80 GLOBAL] + pxor mm6, [t80 GLOBAL] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [t80 GLOBAL] + pxor mm3, [t80 GLOBAL] + movq [rdi], mm3 + movq [rsi+rax*2], mm6 + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s9 GLOBAL] + pmulhw mm2, [s9 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + + movq mm6, [rdi+rax*4] + neg rax + movq mm3, [rdi+rax ] + + pxor mm6, [t80 GLOBAL] + pxor mm3, [t80 GLOBAL] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [t80 GLOBAL] + pxor mm3, [t80 GLOBAL] + movq [rdi+rax ], mm3 + neg rax + movq [rdi+rax*4], mm6 + +;EARLY_BREAK_OUT: + neg rax + add rsi,8 + dec rcx + jnz next8_mbh + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_vertical_edge_mmx) +sym(vp8_mbloop_filter_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 96 ; reserve 96 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[64]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + + movsxd rcx, dword ptr arg(5) ;count +next8_mbv: + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + + ;transpose + movq mm0, [rdi+2*rax] ; 77 76 75 74 73 72 71 70 + movq mm6, [rsi+2*rax] ; 67 66 65 64 63 62 61 60 + + movq mm7, mm6 ; 77 76 75 74 73 72 71 70 + punpckhbw mm7, mm0 ; 77 67 76 66 75 65 74 64 + + punpcklbw mm6, mm0 ; 73 63 72 62 71 61 70 60 + movq mm0, [rsi+rax] ; 57 56 55 54 53 52 51 50 + + movq mm4, [rsi] ; 47 46 45 44 43 42 41 40 + movq mm5, mm4 ; 47 46 45 44 43 42 41 40 + + punpckhbw mm5, mm0 ; 57 47 56 46 55 45 54 44 + punpcklbw mm4, mm0 ; 53 43 52 42 51 41 50 40 + + movq mm3, mm5 ; 57 47 56 46 55 45 54 44 + punpckhwd mm5, mm7 ; 77 67 57 47 76 66 56 46 + + punpcklwd mm3, mm7 ; 75 65 55 45 74 64 54 44 + movq mm2, mm4 ; 53 43 52 42 51 41 50 40 + + punpckhwd mm4, mm6 ; 73 63 53 43 72 62 52 42 + punpcklwd mm2, mm6 ; 71 61 51 41 70 60 50 40 + + neg rax + + movq mm7, [rsi+rax] ; 37 36 35 34 33 32 31 30 + movq mm6, [rsi+rax*2] ; 27 26 25 24 23 22 21 20 + + movq mm1, mm6 ; 27 26 25 24 23 22 21 20 + punpckhbw mm6, mm7 ; 37 27 36 36 35 25 34 24 + + punpcklbw mm1, mm7 ; 33 23 32 22 31 21 30 20 + + movq mm7, [rsi+rax*4]; ; 07 06 05 04 03 02 01 00 + punpckhbw mm7, [rdi+rax*4] ; 17 07 16 06 15 05 14 04 + + movq mm0, mm7 ; 17 07 16 06 15 05 14 04 + punpckhwd mm7, mm6 ; 37 27 17 07 36 26 16 06 + + punpcklwd mm0, mm6 ; 35 25 15 05 34 24 14 04 + movq mm6, mm7 ; 37 27 17 07 36 26 16 06 + + punpckhdq mm7, mm5 ; 77 67 57 47 37 27 17 07 = q3 + punpckldq mm6, mm5 ; 76 66 56 46 36 26 16 06 = q2 + + lea rdx, srct + movq mm5, mm6 ; 76 66 56 46 36 26 16 06 + + movq [rdx+56], mm7 + psubusb mm5, mm7 ; q2-q3 + + + movq [rdx+48], mm6 + psubusb mm7, mm6 ; q3-q2 + + por mm7, mm5; ; mm7=abs (q3-q2) + movq mm5, mm0 ; 35 25 15 05 34 24 14 04 + + punpckhdq mm5, mm3 ; 75 65 55 45 35 25 15 05 = q1 + punpckldq mm0, mm3 ; 74 64 54 44 34 24 15 04 = q0 + + movq mm3, mm5 ; 75 65 55 45 35 25 15 05 = q1 + psubusb mm3, mm6 ; q1-q2 + + psubusb mm6, mm5 ; q2-q1 + por mm6, mm3 ; mm6=abs(q2-q1) + + movq [rdx+40], mm5 ; save q1 + movq [rdx+32], mm0 ; save q0 + + movq mm3, [rsi+rax*4] ; 07 06 05 04 03 02 01 00 + punpcklbw mm3, [rdi+rax*4] ; 13 03 12 02 11 01 10 00 + + movq mm0, mm3 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm1 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm3, mm1 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 31 21 11 01 30 20 10 00 + + punpckldq mm0, mm2 ; 70 60 50 40 30 20 10 00 =p3 + punpckhdq mm1, mm2 ; 71 61 51 41 31 21 11 01 =p2 + + movq [rdx], mm0 ; save p3 + movq [rdx+8], mm1 ; save p2 + + movq mm2, mm1 ; 71 61 51 41 31 21 11 01 =p2 + psubusb mm2, mm0 ; p2-p3 + + psubusb mm0, mm1 ; p3-p2 + por mm0, mm2 ; mm0=abs(p3-p2) + + movq mm2, mm3 ; 33 23 13 03 32 22 12 02 + punpckldq mm2, mm4 ; 72 62 52 42 32 22 12 02 = p1 + + punpckhdq mm3, mm4 ; 73 63 53 43 33 23 13 03 = p0 + movq [rdx+24], mm3 ; save p0 + + movq [rdx+16], mm2 ; save p1 + movq mm5, mm2 ; mm5 = p1 + + psubusb mm2, mm1 ; p1-p2 + psubusb mm1, mm5 ; p2-p1 + + por mm1, mm2 ; mm1=abs(p2-p1) + mov rdx, arg(3) ;limit + + movq mm4, [rdx] ; mm4 = limit + psubusb mm7, mm4 ; abs(q3-q2) > limit + + psubusb mm0, mm4 ; abs(p3-p2) > limit + psubusb mm1, mm4 ; abs(p2-p1) > limit + + psubusb mm6, mm4 ; abs(q2-q1) > limit + por mm7, mm6 ; or + + por mm0, mm1 ; + por mm0, mm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movq mm1, mm5 ; p1 + + movq mm7, mm3 ; mm3=mm7=p0 + psubusb mm7, mm5 ; p0 - p1 + + psubusb mm5, mm3 ; p1 - p0 + por mm5, mm7 ; abs(p1-p0) + + movq t0, mm5 ; save abs(p1-p0) + lea rdx, srct + + psubusb mm5, mm4 ; mm5 = abs(p1-p0) > limit + por mm0, mm5 ; mm0=mask + + movq mm5, [rdx+32] ; mm5=q0 + movq mm7, [rdx+40] ; mm7=q1 + + movq mm6, mm5 ; mm6=q0 + movq mm2, mm7 ; q1 + psubusb mm5, mm7 ; q0-q1 + + psubusb mm7, mm6 ; q1-q0 + por mm7, mm5 ; abs(q1-q0) + + movq t1, mm7 ; save abs(q1-q0) + psubusb mm7, mm4 ; mm7=abs(q1-q0)> limit + + por mm0, mm7 ; mask + + movq mm5, mm2 ; q1 + psubusb mm5, mm1 ; q1-=p1 + psubusb mm1, mm2 ; p1-=q1 + por mm5, mm1 ; abs(p1-q1) + pand mm5, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; + + movq mm2, [rdx] ;flimit mm2 + movq mm1, mm3 ; mm1=mm3=p0 + + movq mm7, mm6 ; mm7=mm6=q0 + psubusb mm1, mm7 ; p0-q0 + + psubusb mm7, mm3 ; q0-p0 + por mm1, mm7 ; abs(q0-p0) + paddusb mm1, mm1 ; abs(q0-p0)*2 + paddusb mm1, mm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + paddb mm2, mm2 ; flimit*2 (less than 255) + paddb mm4, mm2 ; flimit * 2 + limit (less than 255) + + psubusb mm1, mm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por mm1, mm0; ; mask + + pxor mm0, mm0 + pcmpeqb mm1, mm0 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movq mm7, [rdx] + ; + movq mm4, t0 ; get abs (q1 - q0) + psubusb mm4, mm7 ; abs(q1 - q0) > thresh + + movq mm3, t1 ; get abs (p1 - p0) + psubusb mm3, mm7 ; abs(p1 - p0)> thresh + + por mm4, mm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb mm4, mm0 + + pcmpeqb mm0, mm0 + pxor mm4, mm0 + + + + + ; start work on filters + lea rdx, srct + + ; start work on filters + movq mm2, [rdx+16] ; p1 + movq mm7, [rdx+40] ; q1 + pxor mm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + movq mm6, [rdx+24] ; p0 + movq mm0, [rdx+32] ; q0 + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + pxor mm0, [t80 GLOBAL] ; offset to convert to signed values + + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; 1 * (q0 - p0) + (p1 - q1) + paddsb mm2, mm0 ; 2 * (q0 - p0) + paddsb mm2, mm0 ; 3 * (q0 - p0) + (p1 - q1) + pand mm1, mm2 ; mask filter values we don't care about + + ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0 + movq mm2, mm1 ; vp8_filter + pand mm2, mm4; ; Filter2 = vp8_filter & hev + + movq mm5, mm2 ; + paddsb mm5, [t3 GLOBAL]; + + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm5 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm5 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + movq mm5, mm0 ; Filter2 + + paddsb mm2, [t4 GLOBAL] ; vp8_signed_char_clamp(Filter2 + 4) + pxor mm0, mm0 ; 0 + pxor mm7, mm7 ; 0 + + punpcklbw mm0, mm2 ; e0f0g0h0 + psraw mm0, 11 ; sign extended shift right by 3 + punpckhbw mm7, mm2 ; a0b0c0d0 + psraw mm7, 11 ; sign extended shift right by 3 + packsswb mm0, mm7 ; Filter2 >>=3; + + ; mm0= filter2 mm1 = vp8_filter, mm3 =qs0 mm5=s mm4 =hev mm6=ps0 + psubsb mm3, mm0 ; qs0 =qs0 - filter1 + paddsb mm6, mm5 ; ps0 =ps0 + Fitler2 + + ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn mm4, mm1 ; vp8_filter&=~hev + + + ; mm3=qs0, mm4=filter2, mm6=ps0 + + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor mm0, mm0 + + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s27 GLOBAL] + pmulhw mm2, [s27 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + psubsb mm3, mm1 + paddsb mm6, mm1 + + pxor mm3, [t80 GLOBAL] + pxor mm6, [t80 GLOBAL] + movq [rdx+24], mm6 + movq [rdx+32], mm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s18 GLOBAL] + pmulhw mm2, [s18 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm3, [rdx + 40] + movq mm6, [rdx + 16] ; p1 + pxor mm3, [t80 GLOBAL] + pxor mm6, [t80 GLOBAL] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [t80 GLOBAL] + pxor mm3, [t80 GLOBAL] + movq [rdx + 40], mm3 + movq [rdx + 16], mm6 + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor mm1, mm1 + pxor mm2, mm2 + punpcklbw mm1, mm4 + punpckhbw mm2, mm4 + pmulhw mm1, [s9 GLOBAL] + pmulhw mm2, [s9 GLOBAL] + paddw mm1, [s63 GLOBAL] + paddw mm2, [s63 GLOBAL] + psraw mm1, 7 + psraw mm2, 7 + packsswb mm1, mm2 + + movq mm6, [rdx+ 8] + movq mm3, [rdx+48] + + pxor mm6, [t80 GLOBAL] + pxor mm3, [t80 GLOBAL] + + paddsb mm6, mm1 + psubsb mm3, mm1 + + pxor mm6, [t80 GLOBAL] ; mm6 = 71 61 51 41 31 21 11 01 + pxor mm3, [t80 GLOBAL] ; mm3 = 76 66 56 46 36 26 15 06 + + ; tranpose and write back + movq mm0, [rdx] ; mm0 = 70 60 50 40 30 20 10 00 + movq mm1, mm0 ; mm0 = 70 60 50 40 30 20 10 00 + + punpcklbw mm0, mm6 ; mm0 = 31 30 21 20 11 10 01 00 + punpckhbw mm1, mm6 ; mm3 = 71 70 61 60 51 50 41 40 + + movq mm2, [rdx+16] ; mm2 = 72 62 52 42 32 22 12 02 + movq mm6, mm2 ; mm3 = 72 62 52 42 32 22 12 02 + + punpcklbw mm2, [rdx+24] ; mm2 = 33 32 23 22 13 12 03 02 + punpckhbw mm6, [rdx+24] ; mm3 = 73 72 63 62 53 52 43 42 + + movq mm5, mm0 ; mm5 = 31 30 21 20 11 10 01 00 + punpcklwd mm0, mm2 ; mm0 = 13 12 11 10 03 02 01 00 + + punpckhwd mm5, mm2 ; mm5 = 33 32 31 30 23 22 21 20 + movq mm4, mm1 ; mm4 = 71 70 61 60 51 50 41 40 + + punpcklwd mm1, mm6 ; mm1 = 53 52 51 50 43 42 41 40 + punpckhwd mm4, mm6 ; mm4 = 73 72 71 70 63 62 61 60 + + movq mm2, [rdx+32] ; mm2 = 74 64 54 44 34 24 14 04 + punpcklbw mm2, [rdx+40] ; mm2 = 35 34 25 24 15 14 05 04 + + movq mm6, mm3 ; mm6 = 76 66 56 46 36 26 15 06 + punpcklbw mm6, [rdx+56] ; mm6 = 37 36 27 26 17 16 07 06 + + movq mm7, mm2 ; mm7 = 35 34 25 24 15 14 05 04 + punpcklwd mm2, mm6 ; mm2 = 17 16 15 14 07 06 05 04 + + punpckhwd mm7, mm6 ; mm7 = 37 36 35 34 27 26 25 24 + movq mm6, mm0 ; mm6 = 13 12 11 10 03 02 01 00 + + punpckldq mm0, mm2 ; mm0 = 07 06 05 04 03 02 01 00 + punpckhdq mm6, mm2 ; mm6 = 17 16 15 14 13 12 11 10 + + movq [rsi+rax*4], mm0 ; write out + movq [rdi+rax*4], mm6 ; write out + + movq mm0, mm5 ; mm0 = 33 32 31 30 23 22 21 20 + punpckldq mm0, mm7 ; mm0 = 27 26 25 24 23 22 20 20 + + punpckhdq mm5, mm7 ; mm5 = 37 36 35 34 33 32 31 30 + movq [rsi+rax*2], mm0 ; write out + + movq [rdi+rax*2], mm5 ; write out + movq mm2, [rdx+32] ; mm2 = 74 64 54 44 34 24 14 04 + + punpckhbw mm2, [rdx+40] ; mm2 = 75 74 65 64 54 54 45 44 + punpckhbw mm3, [rdx+56] ; mm3 = 77 76 67 66 57 56 47 46 + + movq mm5, mm2 ; mm5 = 75 74 65 64 54 54 45 44 + punpcklwd mm2, mm3 ; mm2 = 57 56 55 54 47 46 45 44 + + punpckhwd mm5, mm3 ; mm5 = 77 76 75 74 67 66 65 64 + movq mm0, mm1 ; mm0= 53 52 51 50 43 42 41 40 + + movq mm3, mm4 ; mm4 = 73 72 71 70 63 62 61 60 + punpckldq mm0, mm2 ; mm0 = 47 46 45 44 43 42 41 40 + + punpckhdq mm1, mm2 ; mm1 = 57 56 55 54 53 52 51 50 + movq [rsi], mm0 ; write out + + movq [rdi], mm1 ; write out + neg rax + + punpckldq mm3, mm5 ; mm3 = 67 66 65 64 63 62 61 60 + punpckhdq mm4, mm5 ; mm4 = 77 76 75 74 73 72 71 60 + + movq [rsi+rax*2], mm3 + movq [rdi+rax*2], mm4 + + lea rsi, [rsi+rax*8] + dec rcx + + jnz next8_mbv + + add rsp, 96 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_horizontal_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_simple_horizontal_edge_mmx) +sym(vp8_loop_filter_simple_horizontal_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + movsxd rcx, dword ptr arg(5) ;count +nexts8_h: + mov rdx, arg(3) ;limit + movq mm7, [rdx] + mov rdx, arg(2) ;flimit ; get flimit + movq mm3, [rdx] ; + paddb mm3, mm3 ; flimit*2 (less than 255) + paddb mm3, mm7 ; flimit * 2 + limit (less than 255) + + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + neg rax + + ; calculate mask + movq mm1, [rsi+2*rax] ; p1 + movq mm0, [rdi] ; q1 + movq mm2, mm1 + movq mm7, mm0 + movq mm4, mm0 + psubusb mm0, mm1 ; q1-=p1 + psubusb mm1, mm4 ; p1-=q1 + por mm1, mm0 ; abs(p1-q1) + pand mm1, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm1, 1 ; abs(p1-q1)/2 + + movq mm5, [rsi+rax] ; p0 + movq mm4, [rsi] ; q0 + movq mm0, mm4 ; q0 + movq mm6, mm5 ; p0 + psubusb mm5, mm4 ; p0-=q0 + psubusb mm4, mm6 ; q0-=p0 + por mm5, mm4 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm1 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + psubusb mm5, mm3 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + pxor mm3, mm3 + pcmpeqb mm5, mm3 + + ; start work on filters + pxor mm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb mm2, mm7 ; p1 - q1 + + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + pxor mm0, [t80 GLOBAL] ; offset to convert to signed values + movq mm3, mm0 ; q0 + psubsb mm0, mm6 ; q0 - p0 + paddsb mm2, mm0 ; p1 - q1 + 1 * (q0 - p0) + paddsb mm2, mm0 ; p1 - q1 + 2 * (q0 - p0) + paddsb mm2, mm0 ; p1 - q1 + 3 * (q0 - p0) + pand mm5, mm2 ; mask filter values we don't care about + + ; do + 4 side + paddsb mm5, [t4 GLOBAL] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + movq mm1, mm5 ; get a copy of filters + psraw mm1, 11 ; arithmetic shift right 11 + psllw mm1, 8 ; shift left 8 to put it back + + por mm0, mm1 ; put the two together to get result + + psubsb mm3, mm0 ; q0-= q0 add + pxor mm3, [t80 GLOBAL] ; unoffset + movq [rsi], mm3 ; write back + + + ; now do +3 side + psubsb mm5, [t1s GLOBAL] ; +3 instead of +4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + psraw mm5, 11 ; arithmetic shift right 11 + psllw mm5, 8 ; shift left 8 to put it back + por mm0, mm5 ; put the two together to get result + + + paddsb mm6, mm0 ; p0+= p0 add + pxor mm6, [t80 GLOBAL] ; unoffset + movq [rsi+rax], mm6 ; write back + + add rsi,8 + neg rax + dec rcx + jnz nexts8_h + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_vertical_edge_mmx +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_simple_vertical_edge_mmx) +sym(vp8_loop_filter_simple_vertical_edge_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4- 2]; ; + movsxd rcx, dword ptr arg(5) ;count +nexts8_v: + + lea rdi, [rsi + rax]; + movd mm0, [rdi + rax * 2] ; xx xx xx xx 73 72 71 70 + + movd mm6, [rsi + rax * 2] ; xx xx xx xx 63 62 61 60 + punpcklbw mm6, mm0 ; 73 63 72 62 71 61 70 60 + + movd mm0, [rsi + rax] ; xx xx xx xx 53 52 51 50 + movd mm4, [rsi] ; xx xx xx xx 43 42 41 40 + + punpcklbw mm4, mm0 ; 53 43 52 42 51 41 50 40 + movq mm5, mm4 ; 53 43 52 42 51 41 50 40 + + punpcklwd mm4, mm6 ; 71 61 51 41 70 60 50 40 + punpckhwd mm5, mm6 ; 73 63 53 43 72 62 52 42 + + neg rax + + movd mm7, [rsi + rax] ; xx xx xx xx 33 32 31 30 + movd mm6, [rsi + rax * 2] ; xx xx xx xx 23 22 21 20 + + punpcklbw mm6, mm7 ; 33 23 32 22 31 21 30 20 + movd mm1, [rdi + rax * 4] ; xx xx xx xx 13 12 11 10 + + movd mm0, [rsi + rax * 4] ; xx xx xx xx 03 02 01 00 + punpcklbw mm0, mm1 ; 13 03 12 02 11 01 10 00 + + movq mm2, mm0 ; 13 03 12 02 11 01 10 00 + punpcklwd mm0, mm6 ; 31 21 11 01 30 20 10 00 + + punpckhwd mm2, mm6 ; 33 23 13 03 32 22 12 02 + movq mm1, mm0 ; 13 03 12 02 11 01 10 00 + + punpckldq mm0, mm4 ; 70 60 50 40 30 20 10 00 = p1 + movq mm3, mm2 ; 33 23 13 03 32 22 12 02 + + punpckhdq mm1, mm4 ; 71 61 51 41 31 21 11 01 = p0 + punpckldq mm2, mm5 ; 72 62 52 42 32 22 12 02 = q0 + + punpckhdq mm3, mm5 ; 73 63 53 43 33 23 13 03 = q1 + + + ; calculate mask + movq mm6, mm0 ; p1 + movq mm7, mm3 ; q1 + psubusb mm7, mm6 ; q1-=p1 + psubusb mm6, mm3 ; p1-=q1 + por mm6, mm7 ; abs(p1-q1) + pand mm6, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw mm6, 1 ; abs(p1-q1)/2 + + movq mm5, mm1 ; p0 + movq mm4, mm2 ; q0 + + psubusb mm5, mm2 ; p0-=q0 + psubusb mm4, mm1 ; q0-=p0 + + por mm5, mm4 ; abs(p0 - q0) + paddusb mm5, mm5 ; abs(p0-q0)*2 + paddusb mm5, mm6 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; get flimit + movq mm7, [rdx] + mov rdx, arg(3) ; get limit + movq mm6, [rdx] + paddb mm7, mm7 ; flimit*2 (less than 255) + paddb mm7, mm6 ; flimit * 2 + limit (less than 255) + + psubusb mm5, mm7 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + pxor mm7, mm7 + pcmpeqb mm5, mm7 ; mm5 = mask + + ; start work on filters + movq t0, mm0 + movq t1, mm3 + + pxor mm0, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor mm3, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb mm0, mm3 ; p1 - q1 + movq mm6, mm1 ; p0 + + movq mm7, mm2 ; q0 + pxor mm6, [t80 GLOBAL] ; offset to convert to signed values + + pxor mm7, [t80 GLOBAL] ; offset to convert to signed values + movq mm3, mm7 ; offseted ; q0 + + psubsb mm7, mm6 ; q0 - p0 + paddsb mm0, mm7 ; p1 - q1 + 1 * (q0 - p0) + + paddsb mm0, mm7 ; p1 - q1 + 2 * (q0 - p0) + paddsb mm0, mm7 ; p1 - q1 + 3 * (q0 - p0) + + pand mm5, mm0 ; mask filter values we don't care about + + paddsb mm5, [t4 GLOBAL] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + + movq mm7, mm5 ; get a copy of filters + psraw mm7, 11 ; arithmetic shift right 11 + psllw mm7, 8 ; shift left 8 to put it back + + por mm0, mm7 ; put the two together to get result + + psubsb mm3, mm0 ; q0-= q0sz add + pxor mm3, [t80 GLOBAL] ; unoffset + + ; now do +3 side + psubsb mm5, [t1s GLOBAL] ; +3 instead of +4 + + movq mm0, mm5 ; get a copy of filters + psllw mm0, 8 ; shift left 8 + psraw mm0, 3 ; arithmetic shift right 11 + psrlw mm0, 8 + + psraw mm5, 11 ; arithmetic shift right 11 + psllw mm5, 8 ; shift left 8 to put it back + por mm0, mm5 ; put the two together to get result + + paddsb mm6, mm0 ; p0+= p0 add + pxor mm6, [t80 GLOBAL] ; unoffset + + + movq mm0, t0 + movq mm4, t1 + + ; mm0 = 70 60 50 40 30 20 10 00 + ; mm6 = 71 61 51 41 31 21 11 01 + ; mm3 = 72 62 52 42 32 22 12 02 + ; mm4 = 73 63 53 43 33 23 13 03 + ; transpose back to write out + + movq mm1, mm0 ; + punpcklbw mm0, mm6 ; 31 30 21 20 11 10 01 00 + + punpckhbw mm1, mm6 ; 71 70 61 60 51 50 41 40 + movq mm2, mm3 ; + + punpcklbw mm2, mm4 ; 33 32 23 22 13 12 03 02 + movq mm5, mm1 ; 71 70 61 60 51 50 41 40 + + punpckhbw mm3, mm4 ; 73 72 63 62 53 52 43 42 + movq mm6, mm0 ; 31 30 21 20 11 10 01 00 + + punpcklwd mm0, mm2 ; 13 12 11 10 03 02 01 00 + punpckhwd mm6, mm2 ; 33 32 31 30 23 22 21 20 + + movd [rsi+rax*4], mm0 ; write 03 02 01 00 + punpcklwd mm1, mm3 ; 53 52 51 50 43 42 41 40 + + psrlq mm0, 32 ; xx xx xx xx 13 12 11 10 + punpckhwd mm5, mm3 ; 73 72 71 70 63 62 61 60 + + movd [rdi+rax*4], mm0 ; write 13 12 11 10 + movd [rsi+rax*2], mm6 ; write 23 22 21 20 + + psrlq mm6, 32 ; 33 32 31 30 + movd [rsi], mm1 ; write 43 42 41 40 + + movd [rsi + rax], mm6 ; write 33 32 31 30 + neg rax + + movd [rsi + rax*2], mm5 ; write 63 62 61 60 + psrlq mm1, 32 ; 53 52 51 50 + + movd [rdi], mm1 ; write out 53 52 51 50 + psrlq mm5, 32 ; 73 72 71 70 + + movd [rdi + rax*2], mm5 ; write 73 72 71 70 + + lea rsi, [rsi+rax*8] ; next 8 + + dec rcx + jnz nexts8_v + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +;void fast_loop_filter_vertical_edges_mmx(unsigned char *y_ptr, +; int y_stride, +; loop_filter_info *lfi) +;{ +; +; +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+4, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+8, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +; vp8_loop_filter_simple_vertical_edge_mmx(y_ptr+12, y_stride, lfi->flim,lfi->lim,lfi->thr,2); +;} + +SECTION_RODATA +align 16 +tfe: + times 8 db 0xfe +align 16 +t80: + times 8 db 0x80 +align 16 +t1s: + times 8 db 0x01 +align 16 +t3: + times 8 db 0x03 +align 16 +t4: + times 8 db 0x04 +align 16 +ones: + times 4 dw 0x0001 +align 16 +s27: + times 4 dw 0x1b00 +align 16 +s18: + times 4 dw 0x1200 +align 16 +s9: + times 4 dw 0x0900 +align 16 +s63: + times 4 dw 0x003f
diff --git a/vp8/common/x86/loopfilter_sse2.asm b/vp8/common/x86/loopfilter_sse2.asm new file mode 100644 index 0000000..5275dfa --- /dev/null +++ b/vp8/common/x86/loopfilter_sse2.asm
@@ -0,0 +1,1978 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void vp8_loop_filter_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_horizontal_edge_sse2) +sym(vp8_loop_filter_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[16]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[16]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + mov rdx, arg(3) ;limit + movdqa xmm7, XMMWORD PTR [rdx] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movdqu xmm2, [rdi+2*rax] ; q3 + movdqu xmm1, [rsi+2*rax] ; q2 + movdqa xmm6, xmm1 ; q2 + psubusb xmm1, xmm2 ; q2-=q3 + psubusb xmm2, xmm6 ; q3-=q2 + por xmm1, xmm2 ; abs(q3-q2) + psubusb xmm1, xmm7 ; + + + movdqu xmm4, [rsi+rax] ; q1 + movdqa xmm3, xmm4 ; q1 + psubusb xmm4, xmm6 ; q1-=q2 + psubusb xmm6, xmm3 ; q2-=q1 + por xmm4, xmm6 ; abs(q2-q1) + + psubusb xmm4, xmm7 + por xmm1, xmm4 + + movdqu xmm4, [rsi] ; q0 + movdqa xmm0, xmm4 ; q0 + psubusb xmm4, xmm3 ; q0-=q1 + psubusb xmm3, xmm0 ; q1-=q0 + por xmm4, xmm3 ; abs(q0-q1) + movdqa t0, xmm4 ; save to t0 + psubusb xmm4, xmm7 + por xmm1, xmm4 + + neg rax ; negate pitch to deal with above border + movdqu xmm2, [rsi+4*rax] ; p3 + movdqu xmm4, [rdi+4*rax] ; p2 + movdqa xmm5, xmm4 ; p2 + psubusb xmm4, xmm2 ; p2-=p3 + psubusb xmm2, xmm5 ; p3-=p2 + por xmm4, xmm2 ; abs(p3 - p2) + psubusb xmm4, xmm7 + por xmm1, xmm4 + + + movdqu xmm4, [rsi+2*rax] ; p1 + movdqa xmm3, xmm4 ; p1 + psubusb xmm4, xmm5 ; p1-=p2 + psubusb xmm5, xmm3 ; p2-=p1 + por xmm4, xmm5 ; abs(p2 - p1) + psubusb xmm4, xmm7 + por xmm1, xmm4 + + movdqa xmm2, xmm3 ; p1 + + movdqu xmm4, [rsi+rax] ; p0 + movdqa xmm5, xmm4 ; p0 + psubusb xmm4, xmm3 ; p0-=p1 + psubusb xmm3, xmm5 ; p1-=p0 + por xmm4, xmm3 ; abs(p1 - p0) + movdqa t1, xmm4 ; save to t1 + psubusb xmm4, xmm7 + por xmm1, xmm4 + + movdqu xmm3, [rdi] ; q1 + movdqa xmm4, xmm3 ; q1 + psubusb xmm3, xmm2 ; q1-=p1 + psubusb xmm2, xmm4 ; p1-=q1 + por xmm2, xmm3 ; abs(p1-q1) + pand xmm2, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm2, 1 ; abs(p1-q1)/2 + + movdqa xmm6, xmm5 ; p0 + movdqu xmm3, [rsi] ; q0 + psubusb xmm5, xmm3 ; p0-=q0 + psubusb xmm3, xmm6 ; q0-=p0 + por xmm5, xmm3 ; abs(p0 - q0) + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; get flimit + movdqa xmm2, [rdx] ; + + paddb xmm2, xmm2 ; flimit*2 (less than 255) + paddb xmm7, xmm2 ; flimit * 2 + limit (less than 255) + + psubusb xmm5, xmm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por xmm1, xmm5 + pxor xmm5, xmm5 + pcmpeqb xmm1, xmm5 ; mask mm1 + + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movdqa xmm7, [rdx] ; + movdqa xmm4, t0 ; get abs (q1 - q0) + psubusb xmm4, xmm7 + movdqa xmm3, t1 ; get abs (p1 - p0) + psubusb xmm3, xmm7 + paddb xmm4, xmm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb xmm4, xmm5 + pcmpeqb xmm5, xmm5 + pxor xmm4, xmm5 + + + ; start work on filters + movdqu xmm2, [rsi+2*rax] ; p1 + movdqu xmm7, [rdi] ; q1 + pxor xmm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb xmm2, xmm7 ; p1 - q1 + pand xmm2, xmm4 ; high var mask (hvm)(p1 - q1) + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + pxor xmm0, [t80 GLOBAL] ; offset to convert to signed values + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + paddsb xmm2, xmm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand xmm1, xmm2 ; mask filter values we don't care about + movdqa xmm2, xmm1 + paddsb xmm1, [t4 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + paddsb xmm2, [t3 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + + pxor xmm0, xmm0 ; + pxor xmm5, xmm5 + punpcklbw xmm0, xmm2 ; + punpckhbw xmm5, xmm2 ; + psraw xmm0, 11 ; + psraw xmm5, 11 + packsswb xmm0, xmm5 + movdqa xmm2, xmm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor xmm0, xmm0 ; 0 + movdqa xmm5, xmm1 ; abcdefgh + punpcklbw xmm0, xmm1 ; e0f0g0h0 + psraw xmm0, 11 ; sign extended shift right by 3 + pxor xmm1, xmm1 ; 0 + punpckhbw xmm1, xmm5 ; a0b0c0d0 + psraw xmm1, 11 ; sign extended shift right by 3 + movdqa xmm5, xmm0 ; save results + + packsswb xmm0, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw xmm5, [ones GLOBAL] + paddsw xmm1, [ones GLOBAL] + psraw xmm5, 1 ; partial shifted one more time for 2nd tap + psraw xmm1, 1 ; partial shifted one more time for 2nd tap + packsswb xmm5, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + pandn xmm4, xmm5 ; high edge variance additive + + paddsb xmm6, xmm2 ; p0+= p0 add + pxor xmm6, [t80 GLOBAL] ; unoffset + movdqu [rsi+rax], xmm6 ; write back + + movdqu xmm6, [rsi+2*rax] ; p1 + pxor xmm6, [t80 GLOBAL] ; reoffset + paddsb xmm6, xmm4 ; p1+= p1 add + pxor xmm6, [t80 GLOBAL] ; unoffset + movdqu [rsi+2*rax], xmm6 ; write back + + psubsb xmm3, xmm0 ; q0-= q0 add + pxor xmm3, [t80 GLOBAL] ; unoffset + movdqu [rsi], xmm3 ; write back + + psubsb xmm7, xmm4 ; q1-= q1 add + pxor xmm7, [t80 GLOBAL] ; unoffset + movdqu [rdi], xmm7 ; write back + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_vertical_edge_sse2) +sym(vp8_loop_filter_vertical_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 96 ; reserve 96 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[16]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[16]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[64]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + mov rdi, rsi ; rdi points to row +1 for indirect addressing + + add rdi, rax + lea rcx, [rdi + rax *8] + + ;transpose + movq xmm7, QWORD PTR [rsi+2*rax] ; 67 66 65 64 63 62 61 60 + movq xmm6, QWORD PTR [rdi+2*rax] ; 77 76 75 74 73 72 71 70 + + punpcklbw xmm7, xmm6 ; 77 67 76 66 75 65 74 64 73 63 72 62 71 61 70 60 + movq xmm5, QWORD PTR [rsi] ; 47 46 45 44 43 42 41 40 + + movq xmm4, QWORD PTR [rsi+rax] ; 57 56 55 54 53 52 51 50 + punpcklbw xmm5, xmm4 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 + + movdqa xmm3, xmm5 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 + punpckhwd xmm5, xmm7 ; 77 67 57 47 76 66 56 46 75 65 55 45 74 64 54 44 + + lea rsi, [rsi+ rax*8] + + punpcklwd xmm3, xmm7 ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + movq xmm6, QWORD PTR [rsi + 2*rax] ; e7 e6 e5 e4 e3 e2 e1 e0 + + movq xmm7, QWORD PTR [rcx + 2*rax] ; f7 f6 f5 f4 f3 f2 f1 f0 + punpcklbw xmm6, xmm7 ; f7 e7 f6 e6 f5 e5 f4 e4 f3 e3 f2 e2 f1 e1 f0 e0 + + movq xmm4, QWORD PTR [rsi] ; c7 c6 c5 c4 c3 c2 c1 c0 + movq xmm7, QWORD PTR [rsi + rax] ; d7 d6 d5 d4 d3 d2 d1 d0 + + punpcklbw xmm4, xmm7 ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 c1 d0 c0 + movdqa xmm7, xmm4 ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 c1 d0 c0 + + punpckhwd xmm7, xmm6 ; f7 e7 d7 c7 f6 e6 d6 c6 f5 e5 d5 c5 f4 e4 d4 c4 + punpcklwd xmm4, xmm6 ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0 + + ; xmm3 xmm4, xmm5 xmm7 in use + neg rax + + lea rsi, [rsi+rax*8] + movq xmm6, QWORD PTR [rsi+rax*2] ; 27 26 25 24 23 22 21 20 + + movq xmm1, QWORD PTR [rsi+rax ] ; 37 36 35 34 33 32 31 30 + punpcklbw xmm6, xmm1 ; 37 27 36 26 35 25 34 24 33 23 32 22 31 21 30 20 + + movq xmm2, QWORD PTR [rsi+rax*4] ; 07 06 05 04 03 02 01 00 + movq xmm1, QWORD PTR [rdi+rax*4] ; 17 16 15 14 13 12 11 10 + + punpcklbw xmm2, xmm1 ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00 + movdqa xmm0, xmm2 + + punpckhwd xmm2, xmm6 ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04 + punpcklwd xmm0, xmm6 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + + movdqa xmm6, xmm2 + punpckldq xmm2, xmm5 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + + punpckhdq xmm6, xmm5 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + ;xmm0 xmm2 xmm3 xmm4, xmm6, xmm7 + + movdqa xmm5, xmm0 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + punpckhdq xmm5, xmm3 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + + punpckldq xmm0, xmm3 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + lea rsi, [rcx+rax] + ; xmm1, xmm3 free + movq xmm1, QWORD PTR [rsi+rax*2] ; a7 a6 a5 a4 a3 a2 a1 a0 + movq xmm3, QWORD PTR [rsi+rax] ; b7 b6 b5 b4 b3 b2 b1 b0 + + punpcklbw xmm1, xmm3 ; + lea rdx, srct ; + + movdqa [rdx+16], xmm1 ; b7 a7 b6 a6 b5 a5 b4 a4 b3 a3 b2 a2 b1 a1 b0 a0 + movq xmm3, QWORD PTR [rsi+rax*4] ; 87 86 85 84 83 82 81 80 + + movq xmm1, QWORD PTR [rcx+rax*4] + punpcklbw xmm3, xmm1 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + + movdqa [rdx], xmm3 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + + punpckhwd xmm3, [rdx+16] ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + movdqa xmm1, xmm3 ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + + punpckhdq xmm1, xmm7 ; f7 e7 d7 c7 b7 a7 97 87 f6 e6 d6 c6 b6 a6 96 86 + punpckldq xmm3, xmm7 ; f5 e5 d5 c5 b5 a5 95 85 f4 e4 d4 c4 b4 a4 94 84 + + movdqa xmm7, xmm2 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + punpcklqdq xmm7, xmm3 ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + + punpckhqdq xmm2, xmm3 ; f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05 + movdqa [rdx+32], xmm7 ; save 4s + + movdqa [rdx+48], xmm2 ; save 5s + movdqa xmm7, xmm6 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + + punpckhqdq xmm7, xmm1 ; f7 e7 d7 c7 b7 a7 97 87 77 67 57 47 37 27 17 07 = q3 + punpcklqdq xmm6, xmm1 ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 = q2 + + ; free 1, 3 xmm7-7s xmm6-6s, xmm2-5s + movq xmm1, QWORD PTR [rdx] ; 93 83 92 82 91 81 90 80 + movq xmm3, QWORD PTR [rdx+16] ; b3 a3 b2 a2 b1 a1 b0 a0 + + punpcklwd xmm1, xmm3 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + movdqa xmm3, xmm1 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + + punpckhdq xmm3, xmm4 ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + punpckldq xmm1, xmm4 ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + + movdqa xmm4, xmm5 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + punpcklqdq xmm5, xmm3 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + + punpckhqdq xmm4, xmm3 ; f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + movdqa [rdx], xmm5 ; save 2s + + movdqa [rdx+16], xmm4 ; save 3s + + movdqa xmm3, xmm6 ; + psubusb xmm3, xmm7 ; q3 - q2 + + psubusb xmm7, xmm6 ; q2 - q3 + por xmm7, xmm3 ; abs(q3-q2) + + movdqa xmm3, xmm2 ; q1 + psubusb xmm3, xmm6 ; q1 - q2 + + psubusb xmm6, xmm2 ; q2 - q1 + por xmm6, xmm3 ; abs(q2-q1) + + + movdqa xmm3, xmm0 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + punpcklqdq xmm0, xmm1 ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + + punpckhqdq xmm3, xmm1 ; f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + movdqa xmm1, xmm3 + + psubusb xmm3, xmm0 ; p2-p3 + psubusb xmm0, xmm1 ; p3-p2 + + por xmm0, xmm3 ; abs(p3-p2) + movdqa xmm3, xmm5 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + + psubusb xmm3, xmm1 ; p1-p2 + psubusb xmm1, xmm5 ; p2-p1 + + por xmm1, xmm3 ; abs(p1-p2) + mov rdx, arg(3) ;limit + + movdqa xmm3, [rdx] ; limit + + psubusb xmm7, xmm3 + psubusb xmm0, xmm3 + + psubusb xmm1, xmm3 + psubusb xmm6, xmm3 + + por xmm7, xmm6 + por xmm0, xmm1 + + por xmm0, xmm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movdqa xmm1, xmm5 ; p1 + + movdqa xmm7, xmm4 ; xmm4 xmm7 = p0 + + psubusb xmm7, xmm5 ; p0 - p1 + psubusb xmm5, xmm4 ; p1 - p0 + + por xmm5, xmm7 ; abs(p1-p0) + movdqa t0, xmm5 ; save abs(p1-p0) + + lea rdx, srct + psubusb xmm5, xmm3 + + por xmm0, xmm5 ; xmm0=mask + movdqa xmm5, [rdx+32] ; xmm5=q0 + + movdqa xmm7, [rdx+48] ; xmm7=q1 + movdqa xmm6, xmm5 ; mm6=q0 + + movdqa xmm2, xmm7 ; q1 + + psubusb xmm5, xmm7 ; q0-q1 + psubusb xmm7, xmm6 ; q1-q0 + + por xmm7, xmm5 ; abs(q1-q0) + movdqa t1, xmm7 ; save abs(q1-q0) + + psubusb xmm7, xmm3 + por xmm0, xmm7 ; mask + + movdqa xmm5, xmm2 ; q1 + psubusb xmm5, xmm1 ; q1-=p1 + psubusb xmm1, xmm2 ; p1-=q1 + por xmm5, xmm1 ; abs(p1-q1) + pand xmm5, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; + movdqa xmm2, [rdx] ;flimit xmm2 + + movdqa xmm1, xmm4 ; xmm1=xmm4=p0 + + movdqa xmm7, xmm6 ; xmm7=xmm6=q0 + psubusb xmm1, xmm7 ; p0-q0 + + psubusb xmm7, xmm4 ; q0-p0 + por xmm1, xmm7 ; abs(q0-p0) + paddusb xmm1, xmm1 ; abs(q0-p0)*2 + paddusb xmm1, xmm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + paddb xmm2, xmm2 ; flimit*2 (less than 255) + paddb xmm3, xmm2 ; flimit * 2 + limit (less than 255) + + psubusb xmm1, xmm3 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + + por xmm1, xmm0; ; mask + + pxor xmm0, xmm0 + pcmpeqb xmm1, xmm0 + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movdqa xmm7, [rdx] + + ; + movdqa xmm4, t0 ; get abs (q1 - q0) + psubusb xmm4, xmm7 + + movdqa xmm3, t1 ; get abs (p1 - p0) + psubusb xmm3, xmm7 + + por xmm4, xmm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb xmm4, xmm0 + + pcmpeqb xmm0, xmm0 + pxor xmm4, xmm0 + + ; start work on filters + lea rdx, srct + + movdqa xmm2, [rdx] ; p1 + movdqa xmm7, [rdx+48] ; q1 + + movdqa xmm6, [rdx+16] ; p0 + movdqa xmm0, [rdx+32] ; q0 + + pxor xmm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm7, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb xmm2, xmm7 ; p1 - q1 + pand xmm2, xmm4 ; high var mask (hvm)(p1 - q1) + + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + pxor xmm0, [t80 GLOBAL] ; offset to convert to signed values + + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + hvm(p1 - q1) + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + hvm(p1 - q1) + + paddsb xmm2, xmm0 ; 3 * (q0 - p0) + hvm(p1 - q1) + pand xmm1, xmm2 ; mask filter values we don't care about + + movdqa xmm2, xmm1 + paddsb xmm1, [t4 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 4 + + paddsb xmm2, [t3 GLOBAL] ; 3* (q0 - p0) + hvm(p1 - q1) + 3 + pxor xmm0, xmm0 ; + + pxor xmm5, xmm5 + punpcklbw xmm0, xmm2 ; + + punpckhbw xmm5, xmm2 ; + psraw xmm0, 11 ; + + psraw xmm5, 11 + packsswb xmm0, xmm5 + + movdqa xmm2, xmm0 ; (3* (q0 - p0) + hvm(p1 - q1) + 3) >> 3; + + pxor xmm0, xmm0 ; 0 + movdqa xmm5, xmm1 ; abcdefgh + + punpcklbw xmm0, xmm1 ; e0f0g0h0 + psraw xmm0, 11 ; sign extended shift right by 3 + + pxor xmm1, xmm1 ; 0 + punpckhbw xmm1, xmm5 ; a0b0c0d0 + + psraw xmm1, 11 ; sign extended shift right by 3 + movdqa xmm5, xmm0 ; save results + + packsswb xmm0, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>3 + paddsw xmm5, [ones GLOBAL] + + paddsw xmm1, [ones GLOBAL] + psraw xmm5, 1 ; partial shifted one more time for 2nd tap + + psraw xmm1, 1 ; partial shifted one more time for 2nd tap + packsswb xmm5, xmm1 ; (3* (q0 - p0) + hvm(p1 - q1) + 4) >>4 + + pandn xmm4, xmm5 ; high edge variance additive + + paddsb xmm6, xmm2 ; p0+= p0 add + pxor xmm6, [t80 GLOBAL] ; unoffset + + ; mm6=p0 ; + movdqa xmm1, [rdx] ; p1 + pxor xmm1, [t80 GLOBAL] ; reoffset + + paddsb xmm1, xmm4 ; p1+= p1 add + pxor xmm1, [t80 GLOBAL] ; unoffset + ; mm6 = p0 mm1 = p1 + + psubsb xmm3, xmm0 ; q0-= q0 add + pxor xmm3, [t80 GLOBAL] ; unoffset + + ; mm3 = q0 + psubsb xmm7, xmm4 ; q1-= q1 add + pxor xmm7, [t80 GLOBAL] ; unoffset + ; mm7 = q1 + + ; tranpose and write back + ; xmm1 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + ; xmm6 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + ; xmm3 = f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + ; xmm7 = f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05 + movdqa xmm2, xmm1 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + punpcklbw xmm2, xmm6 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + + movdqa xmm4, xmm3 ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpckhbw xmm1, xmm6 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + punpcklbw xmm4, xmm7 ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + punpckhbw xmm3, xmm7 ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84 + + movdqa xmm6, xmm2 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpcklwd xmm2, xmm4 ; 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02 + + punpckhwd xmm6, xmm4 ; 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42 + movdqa xmm5, xmm1 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + punpcklwd xmm1, xmm3 ; f5 f4 f3 f2 e5 e4 e3 e2 d5 d4 d3 d2 c5 c4 c3 c2 + punpckhwd xmm5, xmm3 ; b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82 + + ; xmm2 = 35 34 33 32 25 24 23 22 15 14 13 12 05 04 03 02 + ; xmm6 = 75 74 73 72 65 64 63 62 55 54 53 52 45 44 43 42 + ; xmm5 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + ; xmm1 = b5 b4 b3 b2 a5 a4 a3 a2 95 94 93 92 85 84 83 82 + lea rsi, [rsi+rax*8] + + movd [rsi+rax*4+2], xmm2 + psrldq xmm2, 4 + + movd [rdi+rax*4+2], xmm2 + psrldq xmm2, 4 + + movd [rsi+rax*2+2], xmm2 + psrldq xmm2, 4 + + movd [rdi+rax*2+2], xmm2 + movd [rsi+2], xmm6 + + psrldq xmm6, 4 + movd [rdi+2], xmm6 + + psrldq xmm6, 4 + neg rax + + movd [rdi+rax+2], xmm6 + psrldq xmm6, 4 + + movd [rdi+rax*2+2], xmm6 + lea rsi, [rsi+rax*8] + + neg rax + ;;;;;;;;;;;;;;;;;;;;/ + movd [rsi+rax*4+2], xmm1 + psrldq xmm1, 4 + + movd [rcx+rax*4+2], xmm1 + psrldq xmm1, 4 + + movd [rsi+rax*2+2], xmm1 + psrldq xmm1, 4 + + movd [rcx+rax*2+2], xmm1 + psrldq xmm1, 4 + + movd [rsi+2], xmm5 + psrldq xmm5, 4 + + movd [rcx+2], xmm5 + psrldq xmm5, 4 + + neg rax + movd [rcx+rax+2], xmm5 + + psrldq xmm5, 4 + movd [rcx+rax*2+2], xmm5 + + add rsp, 96 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_horizontal_edge_sse2) +sym(vp8_mbloop_filter_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[8]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[8]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + mov rdx, arg(3) ;limit + movdqa xmm7, XMMWORD PTR [rdx] + + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + + ; calculate breakout conditions + movdqa xmm2, XMMWORD PTR [rdi+2*rax] ; q3 + movdqa xmm1, XMMWORD PTR [rsi+2*rax] ; q2 + + movdqa xmm6, xmm1 ; q2 + psubusb xmm1, xmm2 ; q2-=q3 + + + psubusb xmm2, xmm6 ; q3-=q2 + por xmm1, xmm2 ; abs(q3-q2) + + psubusb xmm1, xmm7 + + ; mm1 = abs(q3-q2), mm6 =q2, mm7 = limit + movdqa xmm4, XMMWORD PTR [rsi+rax] ; q1 + movdqa xmm3, xmm4 ; q1 + + psubusb xmm4, xmm6 ; q1-=q2 + psubusb xmm6, xmm3 ; q2-=q1 + + por xmm4, xmm6 ; abs(q2-q1) + psubusb xmm4, xmm7 + + por xmm1, xmm4 + ; mm1 = mask, mm3=q1, mm7 = limit + + movdqa xmm4, XMMWORD PTR [rsi] ; q0 + movdqa xmm0, xmm4 ; q0 + + psubusb xmm4, xmm3 ; q0-=q1 + psubusb xmm3, xmm0 ; q1-=q0 + + por xmm4, xmm3 ; abs(q0-q1) + movdqa t0, xmm4 ; save to t0 + + psubusb xmm4, xmm7 + por xmm1, xmm4 + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + neg rax ; negate pitch to deal with above border + + movdqa xmm2, XMMWORD PTR [rsi+4*rax] ; p3 + movdqa xmm4, XMMWORD PTR [rdi+4*rax] ; p2 + + movdqa xmm5, xmm4 ; p2 + psubusb xmm4, xmm2 ; p2-=p3 + + psubusb xmm2, xmm5 ; p3-=p2 + por xmm4, xmm2 ; abs(p3 - p2) + + psubusb xmm4, xmm7 + por xmm1, xmm4 + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + movdqa xmm4, XMMWORD PTR [rsi+2*rax] ; p1 + movdqa xmm3, xmm4 ; p1 + + psubusb xmm4, xmm5 ; p1-=p2 + psubusb xmm5, xmm3 ; p2-=p1 + + por xmm4, xmm5 ; abs(p2 - p1) + psubusb xmm4, xmm7 + + por xmm1, xmm4 + + movdqa xmm2, xmm3 ; p1 + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) + movdqa xmm4, XMMWORD PTR [rsi+rax] ; p0 + movdqa xmm5, xmm4 ; p0 + + psubusb xmm4, xmm3 ; p0-=p1 + psubusb xmm3, xmm5 ; p1-=p0 + + por xmm4, xmm3 ; abs(p1 - p0) + movdqa t1, xmm4 ; save to t1 + + psubusb xmm4, xmm7 + por xmm1, xmm4 + + ; mm1 = mask, mm0=q0, mm7 = limit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm5 = p0 + movdqa xmm3, XMMWORD PTR [rdi] ; q1 + movdqa xmm4, xmm3 ; q1 + psubusb xmm3, xmm2 ; q1-=p1 + psubusb xmm2, xmm4 ; p1-=q1 + por xmm2, xmm3 ; abs(p1-q1) + pand xmm2, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm2, 1 ; abs(p1-q1)/2 + + movdqa xmm6, xmm5 ; p0 + movdqa xmm3, xmm0 ; q0 + + psubusb xmm5, xmm3 ; p0-=q0 + psubusb xmm3, xmm6 ; q0-=p0 + + por xmm5, xmm3 ; abs(p0 - q0) + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm2 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; get flimit + movdqa xmm2, XMMWORD PTR [rdx] ; + paddb xmm2, xmm2 ; flimit*2 (less than 255) + paddb xmm7, xmm2 ; flimit * 2 + limit (less than 255) + + psubusb xmm5, xmm7 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por xmm1, xmm5 + pxor xmm5, xmm5 + pcmpeqb xmm1, xmm5 ; mask mm1 + ; mm1 = mask, mm0=q0, mm7 = flimit, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movdqa xmm7, XMMWORD PTR [rdx] ; + + movdqa xmm4, t0 ; get abs (q1 - q0) + psubusb xmm4, xmm7 + + movdqa xmm3, t1 ; get abs (p1 - p0) + psubusb xmm3, xmm7 + + paddb xmm4, xmm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb xmm4, xmm5 + + pcmpeqb xmm5, xmm5 + pxor xmm4, xmm5 + ; mm1 = mask, mm0=q0, mm7 = thresh, t0 = abs(q0-q1) t1 = abs(p1-p0) + ; mm6 = p0, mm4=hev + ; start work on filters + movdqa xmm2, XMMWORD PTR [rsi+2*rax] ; p1 + movdqa xmm7, XMMWORD PTR [rdi] ; q1 + + pxor xmm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm7, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb xmm2, xmm7 ; p1 - q1 + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + + pxor xmm0, [t80 GLOBAL] ; offset to convert to signed values + movdqa xmm3, xmm0 ; q0 + + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + (p1 - q1) + + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + paddsb xmm2, xmm0 ; 3 * (q0 - p0) + (p1 - q1) + + pand xmm1, xmm2 ; mask filter values we don't care about + ; mm1 = vp8_filter, mm4=hev, mm6=ps0, mm3=qs0 + movdqa xmm2, xmm1 ; vp8_filter + pand xmm2, xmm4; ; Filter2 = vp8_filter & hev + + + movdqa xmm5, xmm2 ; + paddsb xmm5, [t3 GLOBAL]; + + pxor xmm0, xmm0 ; 0 + pxor xmm7, xmm7 ; 0 + + punpcklbw xmm0, xmm5 ; e0f0g0h0 + psraw xmm0, 11 ; sign extended shift right by 3 + + punpckhbw xmm7, xmm5 ; a0b0c0d0 + psraw xmm7, 11 ; sign extended shift right by 3 + + packsswb xmm0, xmm7 ; Filter2 >>=3; + movdqa xmm5, xmm0 ; Filter2 + + paddsb xmm2, [t4 GLOBAL] ; vp8_signed_char_clamp(Filter2 + 4) + pxor xmm0, xmm0 ; 0 + + pxor xmm7, xmm7 ; 0 + punpcklbw xmm0, xmm2 ; e0f0g0h0 + + psraw xmm0, 11 ; sign extended shift right by 3 + punpckhbw xmm7, xmm2 ; a0b0c0d0 + + psraw xmm7, 11 ; sign extended shift right by 3 + packsswb xmm0, xmm7 ; Filter2 >>=3; + + ; mm0= filter2 mm1 = vp8_filter, mm3 =qs0 mm5=s mm4 =hev mm6=ps0 + psubsb xmm3, xmm0 ; qs0 =qs0 - filter1 + paddsb xmm6, xmm5 ; ps0 =ps0 + Fitler2 + + ; mm1=vp8_filter, mm3=qs0, mm4 =hev mm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn xmm4, xmm1 ; vp8_filter&=~hev + + + ; mm3=qs0, mm4=filter2, mm6=ps0 + + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor xmm0, xmm0 + pxor xmm1, xmm1 + + pxor xmm2, xmm2 + punpcklbw xmm1, xmm4 + + punpckhbw xmm2, xmm4 + pmulhw xmm1, [s27 GLOBAL] + + pmulhw xmm2, [s27 GLOBAL] + paddw xmm1, [s63 GLOBAL] + + paddw xmm2, [s63 GLOBAL] + psraw xmm1, 7 + + psraw xmm2, 7 + packsswb xmm1, xmm2 + + psubsb xmm3, xmm1 + paddsb xmm6, xmm1 + + pxor xmm3, [t80 GLOBAL] + pxor xmm6, [t80 GLOBAL] + + movdqa XMMWORD PTR [rsi+rax], xmm6 + movdqa XMMWORD PTR [rsi], xmm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor xmm1, xmm1 + pxor xmm2, xmm2 + + punpcklbw xmm1, xmm4 + punpckhbw xmm2, xmm4 + + pmulhw xmm1, [s18 GLOBAL] + pmulhw xmm2, [s18 GLOBAL] + + paddw xmm1, [s63 GLOBAL] + paddw xmm2, [s63 GLOBAL] + + psraw xmm1, 7 + psraw xmm2, 7 + + packsswb xmm1, xmm2 + + movdqa xmm3, XMMWORD PTR [rdi] + movdqa xmm6, XMMWORD PTR [rsi+rax*2] ; p1 + + pxor xmm3, [t80 GLOBAL] + pxor xmm6, [t80 GLOBAL] + + paddsb xmm6, xmm1 + psubsb xmm3, xmm1 + + pxor xmm6, [t80 GLOBAL] + pxor xmm3, [t80 GLOBAL] + + movdqa XMMWORD PTR [rdi], xmm3 + movdqa XMMWORD PTR [rsi+rax*2],xmm6 + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor xmm1, xmm1 + pxor xmm2, xmm2 + + punpcklbw xmm1, xmm4 + punpckhbw xmm2, xmm4 + + pmulhw xmm1, [s9 GLOBAL] + pmulhw xmm2, [s9 GLOBAL] + + paddw xmm1, [s63 GLOBAL] + paddw xmm2, [s63 GLOBAL] + + psraw xmm1, 7 + psraw xmm2, 7 + + packsswb xmm1, xmm2 + + + movdqa xmm6, XMMWORD PTR [rdi+rax*4] + neg rax + + movdqa xmm3, XMMWORD PTR [rdi+rax ] + + pxor xmm6, [t80 GLOBAL] + pxor xmm3, [t80 GLOBAL] + + paddsb xmm6, xmm1 + psubsb xmm3, xmm1 + + pxor xmm6, [t80 GLOBAL] + pxor xmm3, [t80 GLOBAL] + + movdqa XMMWORD PTR [rdi+rax ], xmm3 + neg rax + + movdqa XMMWORD PTR [rdi+rax*4], xmm6 + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_mbloop_filter_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_mbloop_filter_vertical_edge_sse2) +sym(vp8_mbloop_filter_vertical_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 160 ; reserve 160 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[16]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[16]; + %define srct [rsp + 32] ;__declspec(align(16)) char srct[128]; + + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi + rax*4 - 4] + lea rdi, [rsi + rax] ; rdi points to row +1 for indirect addressing + + mov rcx, rax + neg rcx + + ; Transpose + movq xmm0, QWORD PTR [rdi+rax*2] ; xx xx xx xx xx xx xx xx 77 76 75 74 73 72 71 70 + movq xmm7, QWORD PTR [rsi+rax*2] ; xx xx xx xx xx xx xx xx 67 66 65 64 63 62 61 60 + + punpcklbw xmm7, xmm0 ; 77 67 76 66 75 65 74 64 73 63 72 62 71 61 70 60 + movq xmm0, QWORD PTR [rsi+rax] ; + + movq xmm5, QWORD PTR [rsi] ; + punpcklbw xmm5, xmm0 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 + + movdqa xmm6, xmm5 ; 57 47 56 46 55 45 54 44 53 43 52 42 51 41 50 40 + punpcklwd xmm5, xmm7 ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + + punpckhwd xmm6, xmm7 ; 77 67 57 47 76 66 56 46 75 65 55 45 74 64 54 44 + movq xmm7, QWORD PTR [rsi + rcx] ; xx xx xx xx xx xx xx xx 37 36 35 34 33 32 31 30 + + movq xmm0, QWORD PTR [rsi + rcx*2] ; xx xx xx xx xx xx xx xx 27 26 25 24 23 22 21 20 + punpcklbw xmm0, xmm7 ; 37 27 36 36 35 25 34 24 33 23 32 22 31 21 30 20 + + movq xmm4, QWORD PTR [rsi + rcx*4] ; xx xx xx xx xx xx xx xx 07 06 05 04 03 02 01 00 + movq xmm7, QWORD PTR [rdi + rcx*4] ; xx xx xx xx xx xx xx xx 17 16 15 14 13 12 11 10 + + punpcklbw xmm4, xmm7 ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00 + movdqa xmm3, xmm4 ; 17 07 16 06 15 05 14 04 13 03 12 02 11 01 10 00 + + punpcklwd xmm3, xmm0 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + punpckhwd xmm4, xmm0 ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04 + + movdqa xmm7, xmm4 ; 37 27 17 07 36 26 16 06 35 25 15 05 34 24 14 04 + movdqa xmm2, xmm3 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + + punpckhdq xmm7, xmm6 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + punpckldq xmm4, xmm6 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + + punpckhdq xmm3, xmm5 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + punpckldq xmm2, xmm5 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + + movdqa t0, xmm2 ; save to free XMM2 + ;movdqa t1, xmm3 + + ; XMM3 XMM4 XMM7 in use + lea rsi, [rsi+rax*8] + lea rdi, [rdi+rax*8] + + movq xmm6, QWORD PTR [rdi+rax*2] ; xx xx xx xx xx xx xx xx f7 f6 f5 f4 f3 f2 f1 f0 + movq xmm5, QWORD PTR [rsi+rax*2] ; xx xx xx xx xx xx xx xx e7 e6 e5 e4 e3 e2 e1 e0 + + punpcklbw xmm5, xmm6 ; f7 e7 f6 e6 f5 e5 f4 e4 f3 e3 f2 e2 f1 e1 f0 e0 + movq xmm6, QWORD PTR [rsi+rax] ; xx xx xx xx xx xx xx xx d7 d6 d5 d4 d3 d2 d1 d0 + + movq xmm1, QWORD PTR [rsi] ; xx xx xx xx xx xx xx xx c7 c6 c5 c4 c3 c2 c1 c0 + punpcklbw xmm1, xmm6 ; d7 c7 d6 c6 d5 c5 d4 c4 d3 c3 d2 c2 d1 e1 d0 c0 + + movdqa xmm6, xmm1 ; + punpckhwd xmm6, xmm5 ; f7 e7 d7 c7 f6 e6 d6 c6 f5 e5 d5 c5 f4 e4 d4 c4 + + punpcklwd xmm1, xmm5 ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0 + movq xmm5, QWORD PTR [rsi+rcx] ; xx xx xx xx xx xx xx xx b7 b6 b5 b4 b3 b2 b1 b0 + + movq xmm0, QWORD PTR [rsi+rcx*2] ; xx xx xx xx xx xx xx xx a7 a6 a5 a4 a3 a2 a1 a0 + punpcklbw xmm0, xmm5 ; b7 a7 b6 a6 b5 a5 b4 a4 b3 a3 b2 a2 b1 a1 b0 a0 + + movq xmm2, QWORD PTR [rsi+rcx*4] ; xx xx xx xx xx xx xx xx 87 86 85 84 83 82 81 80 + movq xmm5, QWORD PTR [rdi+rcx*4] ; xx xx xx xx xx xx xx xx 97 96 95 94 93 92 91 90 + + punpcklbw xmm2, xmm5 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + movdqa xmm5, xmm2 ; 97 87 96 86 95 85 94 84 93 83 92 82 91 81 90 80 + + punpcklwd xmm5, xmm0 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + punpckhwd xmm2, xmm0 ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + + movdqa xmm0, xmm5 + punpckldq xmm0, xmm1 ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + + + punpckhdq xmm5, xmm1 ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + movdqa xmm1, xmm2 ; b7 a7 97 87 b6 a6 96 86 b5 a5 95 85 b4 a4 94 84 + + punpckldq xmm1, xmm6 ; f5 e5 d5 c5 b5 a5 95 85 f4 e4 d4 c4 b4 a4 94 84 + punpckhdq xmm2, xmm6 ; f7 e7 d7 c7 b7 a7 97 87 f6 e6 d6 c6 b6 a6 96 86 + + movdqa xmm6, xmm7 ; 77 67 57 47 37 27 17 07 76 66 56 46 36 26 16 06 + punpcklqdq xmm6, xmm2 ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 + + + lea rdx, srct + punpckhqdq xmm7, xmm2 ; f7 e7 d7 c7 b7 a7 97 87 77 67 57 47 37 27 17 07 + + movdqa [rdx+112], xmm7 ; save 7 + movdqa xmm2, xmm3 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + + movdqa [rdx+96], xmm6 ; save 6 + punpcklqdq xmm2, xmm5 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + + punpckhqdq xmm3, xmm5 ; f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + movdqa [rdx+32], xmm2 ; save 2 + + movdqa xmm5, xmm4 ; 75 65 55 45 35 25 15 05 74 64 54 44 34 24 14 04 + punpcklqdq xmm4, xmm1 ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + + movdqa [rdx+48], xmm3 ; save 3 + punpckhqdq xmm5, xmm1 ; f5 e5 d5 c5 b5 a5 95 85 75 65 55 45 35 25 15 05 + + movdqa [rdx+64], xmm4 ; save 4 + movdqa [rdx+80], xmm5 ; save 5 + + movdqa xmm1, t0 ; get + movdqa xmm2, xmm1 ; + + punpckhqdq xmm1, xmm0 ; f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + punpcklqdq xmm2, xmm0 ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + + movdqa [rdx+16], xmm1 + movdqa [rdx], xmm2 + + movdqa xmm0, xmm6 ; q2 + psubusb xmm0, xmm7 ; q2-q3 + + psubusb xmm7, xmm6 ; q3-q2 + por xmm7, xmm0 ; abs (q3-q2) + + movdqa xmm1, xmm5 ; q1 + psubusb xmm1, xmm6 ; q1-q2 + + psubusb xmm6, xmm5 ; q2-q1 + por xmm6, xmm1 ; abs (q2-q1) + + ;/* + ;movdqa xmm0, xmm4 ; q0 + ;psubusb xmm0 xmm5 ; q0-q1 + ; + ;pusbusb xmm5, xmm4 ; q1-q0 + ;por xmm5, xmm0 ; abs (q1-q0) + ;*/ + + movdqa xmm1, [rdx+16] ; p2 + movdqa xmm0, xmm1 + + psubusb xmm0, xmm2 ; p2 - p3; + psubusb xmm2, xmm1 ; p3 - p2; + + por xmm0, xmm2 ; abs(p2-p3) + + movdqa xmm2, [rdx+32] ; p1 + movdqa xmm5, xmm2 ; p1 + + psubusb xmm5, xmm1 ; p1-p2 + psubusb xmm1, xmm2 ; p2-p1 + + por xmm1, xmm5 ; abs(p2-p1) + mov rdx, arg(3) ;limit + + movdqa xmm4, [rdx] ; limit + psubusb xmm7, xmm4 ; + + + psubusb xmm0, xmm4 ; abs(p3-p2) > limit + psubusb xmm1, xmm4 ; abs(p2-p1) > limit + + psubusb xmm6, xmm4 ; abs(q2-q1) > limit + por xmm7, xmm6 ; or + + por xmm0, xmm1 ; + por xmm0, xmm7 ; abs(q3-q2) > limit || abs(p3-p2) > limit ||abs(p2-p1) > limit || abs(q2-q1) > limit + + movdqa xmm1, xmm2 ; p1 + + movdqa xmm7, xmm3 ; p0 + psubusb xmm7, xmm2 ; p0-p1 + + psubusb xmm2, xmm3 ; p1-p0 + por xmm2, xmm7 ; abs(p1-p0) + + movdqa t0, xmm2 ; save abs(p1-p0) + lea rdx, srct + + psubusb xmm2, xmm4 ; abs(p1-p0)>limit + por xmm0, xmm2 ; mask + + movdqa xmm5, [rdx+64] ; q0 + movdqa xmm7, [rdx+80] ; q1 + + movdqa xmm6, xmm5 ; q0 + movdqa xmm2, xmm7 ; q1 + psubusb xmm5, xmm7 ; q0-q1 + + psubusb xmm7, xmm6 ; q1-q0 + por xmm7, xmm5 ; abs(q1-q0) + + movdqa t1, xmm7 ; save abs(q1-q0) + psubusb xmm7, xmm4 ; abs(q1-q0)> limit + + por xmm0, xmm7 ; mask + + movdqa xmm5, xmm2 ; q1 + psubusb xmm5, xmm1 ; q1-=p1 + psubusb xmm1, xmm2 ; p1-=q1 + por xmm5, xmm1 ; abs(p1-q1) + pand xmm5, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm5, 1 ; abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit ; + movdqa xmm2, [rdx] ; flimit + + movdqa xmm1, xmm3 ; p0 + movdqa xmm7, xmm6 ; q0 + psubusb xmm1, xmm7 ; p0-q0 + psubusb xmm7, xmm3 ; q0-p0 + por xmm1, xmm7 ; abs(q0-p0) + paddusb xmm1, xmm1 ; abs(q0-p0)*2 + paddusb xmm1, xmm5 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + paddb xmm2, xmm2 ; flimit*2 (less than 255) + paddb xmm4, xmm2 ; flimit * 2 + limit (less than 255) + + psubusb xmm1, xmm4 ; abs (p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + por xmm1, xmm0; ; mask + pxor xmm0, xmm0 + pcmpeqb xmm1, xmm0 + + ; calculate high edge variance + mov rdx, arg(4) ;thresh ; get thresh + movdqa xmm7, [rdx] + + movdqa xmm4, t0 ; get abs (q1 - q0) + psubusb xmm4, xmm7 ; abs(q1 - q0) > thresh + + movdqa xmm3, t1 ; get abs (p1 - p0) + psubusb xmm3, xmm7 ; abs(p1 - p0)> thresh + + por xmm4, xmm3 ; abs(q1 - q0) > thresh || abs(p1 - p0) > thresh + pcmpeqb xmm4, xmm0 + + pcmpeqb xmm0, xmm0 + pxor xmm4, xmm0 + + + ; start work on filters + lea rdx, srct + + ; start work on filters + movdqa xmm2, [rdx+32] ; p1 + movdqa xmm7, [rdx+80] ; q1 + + pxor xmm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm7, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb xmm2, xmm7 ; p1 - q1 + movdqa xmm6, [rdx+48] ; p0 + + movdqa xmm0, [rdx+64] ; q0 + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + + pxor xmm0, [t80 GLOBAL] ; offset to convert to signed values + movdqa xmm3, xmm0 ; q0 + + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; 1 * (q0 - p0) + (p1 - q1) + + paddsb xmm2, xmm0 ; 2 * (q0 - p0) + paddsb xmm2, xmm0 ; 3 * (q0 - p0)+ (p1 - q1) + + pand xmm1, xmm2 ; mask filter values we don't care about + + ; xmm1 = vp8_filter, xmm4=hev, xmm6=ps0, xmm3=qs0 + movdqa xmm2, xmm1 ; vp8_filter + pand xmm2, xmm4; ; Filter2 = vp8_filter & hev + + movdqa xmm5, xmm2 + paddsb xmm5, [t3 GLOBAL] + + pxor xmm0, xmm0 ; 0 + pxor xmm7, xmm7 ; 0 + + punpcklbw xmm0, xmm5 ; e0f0g0h0 + psraw xmm0, 11 ; sign extended shift right by 3 + + punpckhbw xmm7, xmm5 ; a0b0c0d0 + psraw xmm7, 11 ; sign extended shift right by 3 + + packsswb xmm0, xmm7 ; Filter2 >>=3; + movdqa xmm5, xmm0 ; Filter2 + + paddsb xmm2, [t4 GLOBAL] ; vp8_signed_char_clamp(Filter2 + 4) + pxor xmm0, xmm0 ; 0 + + pxor xmm7, xmm7 ; 0 + punpcklbw xmm0, xmm2 ; e0f0g0h0 + + psraw xmm0, 11 ; sign extended shift right by 3 + punpckhbw xmm7, xmm2 ; a0b0c0d0 + + psraw xmm7, 11 ; sign extended shift right by 3 + packsswb xmm0, xmm7 ; Filter2 >>=3; + + ; xmm0= filter2 xmm1 = vp8_filter, xmm3 =qs0 xmm5=s xmm4 =hev xmm6=ps0 + psubsb xmm3, xmm0 ; qs0 =qs0 - filter1 + paddsb xmm6, xmm5 ; ps0 =ps0 + Fitler2 + + + ; xmm1=vp8_filter, xmm3=qs0, xmm4 =hev xmm6=ps0 + ; vp8_filter &= ~hev; + ; Filter2 = vp8_filter; + pandn xmm4, xmm1 ; vp8_filter&=~hev + + ; xmm3=qs0, xmm4=filter2, xmm6=ps0 + ; u = vp8_signed_char_clamp((63 + Filter2 * 27)>>7); + ; s = vp8_signed_char_clamp(qs0 - u); + ; *oq0 = s^0x80; + ; s = vp8_signed_char_clamp(ps0 + u); + ; *op0 = s^0x80; + pxor xmm0, xmm0 + pxor xmm1, xmm1 + + pxor xmm2, xmm2 + punpcklbw xmm1, xmm4 + + punpckhbw xmm2, xmm4 + pmulhw xmm1, [s27 GLOBAL] + + pmulhw xmm2, [s27 GLOBAL] + paddw xmm1, [s63 GLOBAL] + + paddw xmm2, [s63 GLOBAL] + psraw xmm1, 7 + + psraw xmm2, 7 + packsswb xmm1, xmm2 + + psubsb xmm3, xmm1 + paddsb xmm6, xmm1 + + pxor xmm3, [t80 GLOBAL] + pxor xmm6, [t80 GLOBAL] + + movdqa [rdx+48], xmm6 + movdqa [rdx+64], xmm3 + + ; roughly 2/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 18)>>7); + ; s = vp8_signed_char_clamp(qs1 - u); + ; *oq1 = s^0x80; + ; s = vp8_signed_char_clamp(ps1 + u); + ; *op1 = s^0x80; + pxor xmm1, xmm1 + pxor xmm2, xmm2 + + punpcklbw xmm1, xmm4 + punpckhbw xmm2, xmm4 + + pmulhw xmm1, [s18 GLOBAL] + pmulhw xmm2, [s18 GLOBAL] + + paddw xmm1, [s63 GLOBAL] + paddw xmm2, [s63 GLOBAL] + + psraw xmm1, 7 + psraw xmm2, 7 + + packsswb xmm1, xmm2 + + movdqa xmm3, [rdx + 80] ;/q1 + movdqa xmm6, [rdx + 32] ; p1 + + pxor xmm3, [t80 GLOBAL] + pxor xmm6, [t80 GLOBAL] + + paddsb xmm6, xmm1 + psubsb xmm3, xmm1 + + pxor xmm6, [t80 GLOBAL] + pxor xmm3, [t80 GLOBAL] + + movdqa [rdx + 80], xmm3 + movdqa [rdx + 32], xmm6 + + + ; roughly 1/7th difference across boundary + ; u = vp8_signed_char_clamp((63 + Filter2 * 9)>>7); + ; s = vp8_signed_char_clamp(qs2 - u); + ; *oq2 = s^0x80; + ; s = vp8_signed_char_clamp(ps2 + u); + ; *op2 = s^0x80; + pxor xmm1, xmm1 + pxor xmm2, xmm2 + + punpcklbw xmm1, xmm4 + punpckhbw xmm2, xmm4 + + pmulhw xmm1, [s9 GLOBAL] + pmulhw xmm2, [s9 GLOBAL] + + paddw xmm1, [s63 GLOBAL] + paddw xmm2, [s63 GLOBAL] + + psraw xmm1, 7 + psraw xmm2, 7 + + packsswb xmm1, xmm2 + + movdqa xmm6, [rdx+16] + movdqa xmm3, [rdx+96] + + pxor xmm6, [t80 GLOBAL] + pxor xmm3, [t80 GLOBAL] + + paddsb xmm6, xmm1 + psubsb xmm3, xmm1 + + pxor xmm6, [t80 GLOBAL] ; xmm6 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + pxor xmm3, [t80 GLOBAL] ; xmm3 = f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 15 06 + + + ; transpose and write back + movdqa xmm0, [rdx] ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + movdqa xmm1, xmm0 ; f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + + punpcklbw xmm0, xmm6 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpckhbw xmm1, xmm6 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + movdqa xmm2, [rdx+32] ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + movdqa xmm6, xmm2 ; f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + + punpcklbw xmm2, [rdx+48] ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpckhbw xmm6, [rdx+48] ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + movdqa xmm5, xmm0 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpcklwd xmm0, xmm2 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + + punpckhwd xmm5, xmm2 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + movdqa xmm4, xmm1 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + punpcklwd xmm1, xmm6 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckhwd xmm4, xmm6 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + + movdqa xmm2, [rdx+64] ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpcklbw xmm2, [rdx+80] ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + + movdqa xmm6, xmm3 ; f6 e6 d6 c6 b6 a6 96 86 76 66 56 46 36 26 16 06 + punpcklbw xmm6, [rdx+112] ; 77 76 67 66 57 56 47 46 37 36 27 26 17 16 07 06 + + movdqa xmm7, xmm2 ; 75 74 65 64 55 54 45 44 35 34 25 24 15 14 05 04 + punpcklwd xmm2, xmm6 ; 37 36 35 34 27 26 25 24 17 16 15 14 07 06 05 04 + + punpckhwd xmm7, xmm6 ; 77 76 75 74 67 66 65 64 57 56 55 54 47 46 45 44 + movdqa xmm6, xmm0 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + + punpckldq xmm0, xmm2 ; 17 16 15 14 13 12 11 10 07 06 05 04 03 02 01 00 + punpckhdq xmm6, xmm2 ; 37 36 35 34 33 32 31 30 27 26 25 24 23 22 21 20 + + lea rsi, [rsi+rcx*8] + lea rdi, [rdi+rcx*8] + + movq QWORD PTR [rsi+rcx*4], xmm0 + psrldq xmm0, 8 + + movq QWORD PTR [rsi+rcx*2], xmm6 + psrldq xmm6, 8 + + movq QWORD PTR [rdi+rcx*4], xmm0 + movq QWORD PTR [rsi+rcx], xmm6 + + movdqa xmm0, xmm5 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + punpckldq xmm0, xmm7 ; 57 56 55 54 53 52 51 50 47 46 45 44 43 42 41 40 + + punpckhdq xmm5, xmm7 ; 77 76 75 74 73 72 71 70 67 66 65 64 63 62 61 60 + + movq QWORD PTR [rsi], xmm0 + psrldq xmm0, 8 + + movq QWORD PTR [rsi+rax*2], xmm5 + psrldq xmm5, 8 + + movq QWORD PTR [rsi+rax], xmm0 + movq QWORD PTR [rdi+rax*2], xmm5 + + movdqa xmm2, [rdx+64] ; f4 e4 d4 c4 b4 a4 94 84 74 64 54 44 34 24 14 04 + punpckhbw xmm2, [rdx+80] ; f5 f4 e5 e4 d5 d4 c5 c4 b5 b4 a5 a4 95 94 85 84 + + punpckhbw xmm3, [rdx+112] ; f7 f6 e7 e6 d7 d6 c7 c6 b7 b6 a7 a6 97 96 87 86 + movdqa xmm0, xmm2 + + punpcklwd xmm0, xmm3 ; b7 b6 b4 b4 a7 a6 a5 a4 97 96 95 94 87 86 85 84 + punpckhwd xmm2, xmm3 ; f7 f6 f5 f4 e7 e6 e5 e4 d7 d6 d5 d4 c7 c6 c5 c4 + + movdqa xmm3, xmm1 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckldq xmm1, xmm0 ; 97 96 95 94 93 92 91 90 87 86 85 83 84 82 81 80 + + punpckhdq xmm3, xmm0 ; b7 b6 b5 b4 b3 b2 b1 b0 a7 a6 a5 a4 a3 a2 a1 a0 + + lea rsi, [rsi+rax*8] + lea rdi, [rdi+rax*8] + + movq QWORD PTR [rsi+rcx*4], xmm1 + psrldq xmm1, 8 + + movq QWORD PTR [rsi+rcx*2], xmm3 + psrldq xmm3, 8 + + movq QWORD PTR [rdi+rcx*4], xmm1 + movq QWORD PTR [rsi+rcx], xmm3 + + movdqa xmm1, xmm4 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + punpckldq xmm1, xmm2 ; d7 d6 d5 d4 d3 d2 d1 d0 c7 c6 c5 c4 c3 c2 c1 c0 + + punpckhdq xmm4, xmm2 ; f7 f6 f4 f4 f3 f2 f1 f0 e7 e6 e5 e4 e3 e2 e1 e0 + movq QWORD PTR [rsi], xmm1 + + psrldq xmm1, 8 + + movq QWORD PTR [rsi+rax*2], xmm4 + psrldq xmm4, 8 + + movq QWORD PTR [rsi+rax], xmm1 + movq QWORD PTR [rdi+rax*2], xmm4 + + add rsp, 160 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_horizontal_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_simple_horizontal_edge_sse2) +sym(vp8_loop_filter_simple_horizontal_edge_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + mov rdx, arg(2) ;flimit ; get flimit + movdqa xmm3, XMMWORD PTR [rdx] + mov rdx, arg(3) ;limit + movdqa xmm7, XMMWORD PTR [rdx] + + paddb xmm3, xmm3 ; flimit*2 (less than 255) + paddb xmm3, xmm7 ; flimit * 2 + limit (less than 255) + + mov rdi, rsi ; rdi points to row +1 for indirect addressing + add rdi, rax + neg rax + + ; calculate mask + movdqu xmm1, [rsi+2*rax] ; p1 + movdqu xmm0, [rdi] ; q1 + movdqa xmm2, xmm1 + movdqa xmm7, xmm0 + movdqa xmm4, xmm0 + psubusb xmm0, xmm1 ; q1-=p1 + psubusb xmm1, xmm4 ; p1-=q1 + por xmm1, xmm0 ; abs(p1-q1) + pand xmm1, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm1, 1 ; abs(p1-q1)/2 + + movdqu xmm5, [rsi+rax] ; p0 + movdqu xmm4, [rsi] ; q0 + movdqa xmm0, xmm4 ; q0 + movdqa xmm6, xmm5 ; p0 + psubusb xmm5, xmm4 ; p0-=q0 + psubusb xmm4, xmm6 ; q0-=p0 + por xmm5, xmm4 ; abs(p0 - q0) + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm1 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + psubusb xmm5, xmm3 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + pxor xmm3, xmm3 + pcmpeqb xmm5, xmm3 + + ; start work on filters + pxor xmm2, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm7, [t80 GLOBAL] ; q1 offset to convert to signed values + psubsb xmm2, xmm7 ; p1 - q1 + + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + pxor xmm0, [t80 GLOBAL] ; offset to convert to signed values + movdqa xmm3, xmm0 ; q0 + psubsb xmm0, xmm6 ; q0 - p0 + paddsb xmm2, xmm0 ; p1 - q1 + 1 * (q0 - p0) + paddsb xmm2, xmm0 ; p1 - q1 + 2 * (q0 - p0) + paddsb xmm2, xmm0 ; p1 - q1 + 3 * (q0 - p0) + pand xmm5, xmm2 ; mask filter values we don't care about + + ; do + 4 side + paddsb xmm5, [t4 GLOBAL] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movdqa xmm0, xmm5 ; get a copy of filters + psllw xmm0, 8 ; shift left 8 + psraw xmm0, 3 ; arithmetic shift right 11 + psrlw xmm0, 8 + movdqa xmm1, xmm5 ; get a copy of filters + psraw xmm1, 11 ; arithmetic shift right 11 + psllw xmm1, 8 ; shift left 8 to put it back + + por xmm0, xmm1 ; put the two together to get result + + psubsb xmm3, xmm0 ; q0-= q0 add + pxor xmm3, [t80 GLOBAL] ; unoffset + movdqu [rsi], xmm3 ; write back + + ; now do +3 side + psubsb xmm5, [t1s GLOBAL] ; +3 instead of +4 + + movdqa xmm0, xmm5 ; get a copy of filters + psllw xmm0, 8 ; shift left 8 + psraw xmm0, 3 ; arithmetic shift right 11 + psrlw xmm0, 8 + psraw xmm5, 11 ; arithmetic shift right 11 + psllw xmm5, 8 ; shift left 8 to put it back + por xmm0, xmm5 ; put the two together to get result + + + paddsb xmm6, xmm0 ; p0+= p0 add + pxor xmm6, [t80 GLOBAL] ; unoffset + movdqu [rsi+rax], xmm6 ; write back + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_loop_filter_simple_vertical_edge_sse2 +;( +; unsigned char *src_ptr, +; int src_pixel_step, +; const char *flimit, +; const char *limit, +; const char *thresh, +; int count +;) +global sym(vp8_loop_filter_simple_vertical_edge_sse2) +sym(vp8_loop_filter_simple_vertical_edge_sse2): + push rbp ; save old base pointer value. + mov rbp, rsp ; set new base pointer value. + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx ; save callee-saved reg + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 32 ; reserve 32 bytes + %define t0 [rsp + 0] ;__declspec(align(16)) char t0[16]; + %define t1 [rsp + 16] ;__declspec(align(16)) char t1[16]; + + mov rsi, arg(0) ;src_ptr + movsxd rax, dword ptr arg(1) ;src_pixel_step ; destination pitch? + + lea rsi, [rsi - 2 ] + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movdqu xmm0, [rsi] ; (high 96 bits unused) 03 02 01 00 + movdqu xmm1, [rdx] ; (high 96 bits unused) 43 42 41 40 + movdqu xmm2, [rdi] ; 13 12 11 10 + movdqu xmm3, [rcx] ; 53 52 51 50 + punpckldq xmm0, xmm1 ; (high 64 bits unused) 43 42 41 40 03 02 01 00 + punpckldq xmm2, xmm3 ; 53 52 51 50 13 12 11 10 + + movdqu xmm4, [rsi + rax*2] ; 23 22 21 20 + movdqu xmm5, [rdx + rax*2] ; 63 62 61 60 + movdqu xmm6, [rdi + rax*2] ; 33 32 31 30 + movdqu xmm7, [rcx + rax*2] ; 73 72 71 70 + punpckldq xmm4, xmm5 ; 63 62 61 60 23 22 21 20 + punpckldq xmm6, xmm7 ; 73 72 71 70 33 32 31 30 + + punpcklbw xmm0, xmm2 ; 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00 + punpcklbw xmm4, xmm6 ; 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20 + + movdqa xmm1, xmm0 + punpcklwd xmm0, xmm4 ; 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm4 ; 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40 + + movdqa xmm2, xmm0 + punpckldq xmm0, xmm1 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + punpckhdq xmm2, xmm1 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + + movdqa t0, xmm0 ; save to t0 + movdqa t1, xmm2 ; save to t1 + + lea rsi, [rsi + rax*8] + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movdqu xmm4, [rsi] ; 83 82 81 80 + movdqu xmm1, [rdx] ; c3 c2 c1 c0 + movdqu xmm6, [rdi] ; 93 92 91 90 + movdqu xmm3, [rcx] ; d3 d2 d1 d0 + punpckldq xmm4, xmm1 ; c3 c2 c1 c0 83 82 81 80 + punpckldq xmm6, xmm3 ; d3 d2 d1 d0 93 92 91 90 + + movdqu xmm0, [rsi + rax*2] ; a3 a2 a1 a0 + movdqu xmm5, [rdx + rax*2] ; e3 e2 e1 e0 + movdqu xmm2, [rdi + rax*2] ; b3 b2 b1 b0 + movdqu xmm7, [rcx + rax*2] ; f3 f2 f1 f0 + punpckldq xmm0, xmm5 ; e3 e2 e1 e0 a3 a2 a1 a0 + punpckldq xmm2, xmm7 ; f3 f2 f1 f0 b3 b2 b1 b0 + + punpcklbw xmm4, xmm6 ; d3 c3 d2 c2 d1 c1 d0 c0 93 83 92 82 91 81 90 80 + punpcklbw xmm0, xmm2 ; f3 e3 f2 e2 f1 e1 f0 e0 b3 a3 b2 a2 b1 a1 b0 a0 + + movdqa xmm1, xmm4 + punpcklwd xmm4, xmm0 ; b3 a3 93 83 b2 a2 92 82 b1 a1 91 81 b0 a0 90 80 + punpckhwd xmm1, xmm0 ; f3 e3 d3 c3 f2 e2 d2 c2 f1 e1 d1 c1 f0 e0 d0 c0 + + movdqa xmm6, xmm4 + punpckldq xmm4, xmm1 ; f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80 + punpckhdq xmm6, xmm1 ; f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82 + + movdqa xmm0, t0 ; 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00 + movdqa xmm2, t1 ; 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02 + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + + punpcklqdq xmm0, xmm4 ; p1 f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + punpckhqdq xmm1, xmm4 ; p0 f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + punpcklqdq xmm2, xmm6 ; q0 f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + punpckhqdq xmm3, xmm6 ; q1 f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + + ; calculate mask + movdqa xmm6, xmm0 ; p1 + movdqa xmm7, xmm3 ; q1 + psubusb xmm7, xmm0 ; q1-=p1 + psubusb xmm6, xmm3 ; p1-=q1 + por xmm6, xmm7 ; abs(p1-q1) + pand xmm6, [tfe GLOBAL] ; set lsb of each byte to zero + psrlw xmm6, 1 ; abs(p1-q1)/2 + + movdqa xmm5, xmm1 ; p0 + movdqa xmm4, xmm2 ; q0 + psubusb xmm5, xmm2 ; p0-=q0 + psubusb xmm4, xmm1 ; q0-=p0 + por xmm5, xmm4 ; abs(p0 - q0) + paddusb xmm5, xmm5 ; abs(p0-q0)*2 + paddusb xmm5, xmm6 ; abs (p0 - q0) *2 + abs(p1-q1)/2 + + mov rdx, arg(2) ;flimit + movdqa xmm7, XMMWORD PTR [rdx] + mov rdx, arg(3) ; get limit + movdqa xmm6, XMMWORD PTR [rdx] + paddb xmm7, xmm7 ; flimit*2 (less than 255) + paddb xmm7, xmm6 ; flimit * 2 + limit (less than 255) + + psubusb xmm5, xmm7 ; abs(p0 - q0) *2 + abs(p1-q1)/2 > flimit * 2 + limit + pxor xmm7, xmm7 + pcmpeqb xmm5, xmm7 ; mm5 = mask + + ; start work on filters + movdqa t0, xmm0 + movdqa t1, xmm3 + + pxor xmm0, [t80 GLOBAL] ; p1 offset to convert to signed values + pxor xmm3, [t80 GLOBAL] ; q1 offset to convert to signed values + + psubsb xmm0, xmm3 ; p1 - q1 + movdqa xmm6, xmm1 ; p0 + + movdqa xmm7, xmm2 ; q0 + pxor xmm6, [t80 GLOBAL] ; offset to convert to signed values + + pxor xmm7, [t80 GLOBAL] ; offset to convert to signed values + movdqa xmm3, xmm7 ; offseted ; q0 + + psubsb xmm7, xmm6 ; q0 - p0 + paddsb xmm0, xmm7 ; p1 - q1 + 1 * (q0 - p0) + + paddsb xmm0, xmm7 ; p1 - q1 + 2 * (q0 - p0) + paddsb xmm0, xmm7 ; p1 - q1 + 3 * (q0 - p0) + + pand xmm5, xmm0 ; mask filter values we don't care about + + + paddsb xmm5, [t4 GLOBAL] ; 3* (q0 - p0) + (p1 - q1) + 4 + + movdqa xmm0, xmm5 ; get a copy of filters + psllw xmm0, 8 ; shift left 8 + + psraw xmm0, 3 ; arithmetic shift right 11 + psrlw xmm0, 8 + + movdqa xmm7, xmm5 ; get a copy of filters + psraw xmm7, 11 ; arithmetic shift right 11 + + psllw xmm7, 8 ; shift left 8 to put it back + por xmm0, xmm7 ; put the two together to get result + + psubsb xmm3, xmm0 ; q0-= q0sz add + pxor xmm3, [t80 GLOBAL] ; unoffset q0 + + ; now do +3 side + psubsb xmm5, [t1s GLOBAL] ; +3 instead of +4 + movdqa xmm0, xmm5 ; get a copy of filters + + psllw xmm0, 8 ; shift left 8 + psraw xmm0, 3 ; arithmetic shift right 11 + + psrlw xmm0, 8 + psraw xmm5, 11 ; arithmetic shift right 11 + + psllw xmm5, 8 ; shift left 8 to put it back + por xmm0, xmm5 ; put the two together to get result + + paddsb xmm6, xmm0 ; p0+= p0 add + pxor xmm6, [t80 GLOBAL] ; unoffset p0 + + movdqa xmm0, t0 ; p1 + movdqa xmm4, t1 ; q1 + + ; transpose back to write out + ; p1 f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00 + ; p0 f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01 + ; q0 f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02 + ; q1 f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03 + movdqa xmm1, xmm0 + punpcklbw xmm0, xmm6 ; 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00 + punpckhbw xmm1, xmm6 ; f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80 + + movdqa xmm5, xmm3 + punpcklbw xmm3, xmm4 ; 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02 + punpckhbw xmm5, xmm4 ; f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82 + + movdqa xmm2, xmm0 + punpcklwd xmm0, xmm3 ; 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 + punpckhwd xmm2, xmm3 ; 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40 + + movdqa xmm3, xmm1 + punpcklwd xmm1, xmm5 ; b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80 + punpckhwd xmm3, xmm5 ; f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0 + + ; write out order: xmm0 xmm2 xmm1 xmm3 + lea rdx, [rsi + rax*4] + + movd [rsi], xmm1 ; write the second 8-line result + psrldq xmm1, 4 + movd [rdi], xmm1 + psrldq xmm1, 4 + movd [rsi + rax*2], xmm1 + psrldq xmm1, 4 + movd [rdi + rax*2], xmm1 + + movd [rdx], xmm3 + psrldq xmm3, 4 + movd [rcx], xmm3 + psrldq xmm3, 4 + movd [rdx + rax*2], xmm3 + psrldq xmm3, 4 + movd [rcx + rax*2], xmm3 + + neg rax + lea rsi, [rsi + rax*8] + neg rax + lea rdi, [rsi + rax] + lea rdx, [rsi + rax*4] + lea rcx, [rdx + rax] + + movd [rsi], xmm0 ; write the first 8-line result + psrldq xmm0, 4 + movd [rdi], xmm0 + psrldq xmm0, 4 + movd [rsi + rax*2], xmm0 + psrldq xmm0, 4 + movd [rdi + rax*2], xmm0 + + movd [rdx], xmm2 + psrldq xmm2, 4 + movd [rcx], xmm2 + psrldq xmm2, 4 + movd [rdx + rax*2], xmm2 + psrldq xmm2, 4 + movd [rcx + rax*2], xmm2 + + add rsp, 32 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +SECTION_RODATA +align 16 +tfe: + times 16 db 0xfe +align 16 +t80: + times 16 db 0x80 +align 16 +t1s: + times 16 db 0x01 +align 16 +t3: + times 16 db 0x03 +align 16 +t4: + times 16 db 0x04 +align 16 +ones: + times 8 dw 0x0001 +align 16 +s27: + times 8 dw 0x1b00 +align 16 +s18: + times 8 dw 0x1200 +align 16 +s9: + times 8 dw 0x0900 +align 16 +s63: + times 8 dw 0x003f
diff --git a/vp8/common/x86/loopfilter_x86.c b/vp8/common/x86/loopfilter_x86.c new file mode 100644 index 0000000..143ee74 --- /dev/null +++ b/vp8/common/x86/loopfilter_x86.c
@@ -0,0 +1,274 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "loopfilter.h" + +prototype_loopfilter(vp8_loop_filter_horizontal_edge_c); +prototype_loopfilter(vp8_loop_filter_vertical_edge_c); +prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_c); +prototype_loopfilter(vp8_mbloop_filter_vertical_edge_c); +prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_c); +prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_c); + +prototype_loopfilter(vp8_mbloop_filter_vertical_edge_mmx); +prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_mmx); +prototype_loopfilter(vp8_loop_filter_vertical_edge_mmx); +prototype_loopfilter(vp8_loop_filter_horizontal_edge_mmx); +prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_mmx); +prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_mmx); + +prototype_loopfilter(vp8_loop_filter_vertical_edge_sse2); +prototype_loopfilter(vp8_loop_filter_horizontal_edge_sse2); +prototype_loopfilter(vp8_mbloop_filter_vertical_edge_sse2); +prototype_loopfilter(vp8_mbloop_filter_horizontal_edge_sse2); +prototype_loopfilter(vp8_loop_filter_simple_vertical_edge_sse2); +prototype_loopfilter(vp8_loop_filter_simple_horizontal_edge_sse2); +prototype_loopfilter(vp8_fast_loop_filter_vertical_edges_sse2); + +#if HAVE_MMX +// Horizontal MB filtering +void vp8_loop_filter_mbh_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_horizontal_edge_mmx(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + + +void vp8_loop_filter_mbhs_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + + +// Vertical MB Filtering +void vp8_loop_filter_mbv_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_vertical_edge_mmx(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_mmx(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_mmx(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + + +void vp8_loop_filter_mbvs_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + + +// Horizontal B Filtering +void vp8_loop_filter_bh_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_mmx(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_mmx(u_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_mmx(v_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + + +void vp8_loop_filter_bhs_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_mmx(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + + +// Vertical B Filtering +void vp8_loop_filter_bv_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_vertical_edge_mmx(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_mmx(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_mmx(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_mmx(u_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_mmx(v_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + + +void vp8_loop_filter_bvs_mmx(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_mmx(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} +#endif + + +// Horizontal MB filtering +#if HAVE_SSE2 +void vp8_loop_filter_mbh_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_horizontal_edge_sse2(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_horizontal_edge_mmx(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + + +void vp8_loop_filter_mbhs_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + + +// Vertical MB Filtering +void vp8_loop_filter_mbv_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_mbloop_filter_vertical_edge_sse2(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); + + if (u_ptr) + vp8_mbloop_filter_vertical_edge_mmx(u_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); + + if (v_ptr) + vp8_mbloop_filter_vertical_edge_mmx(v_ptr, uv_stride, lfi->uvmbflim, lfi->uvlim, lfi->uvmbthr, 1); +} + + +void vp8_loop_filter_mbvs_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr, y_stride, lfi->mbflim, lfi->lim, lfi->mbthr, 2); +} + + +// Horizontal B Filtering +void vp8_loop_filter_bh_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_horizontal_edge_sse2(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_horizontal_edge_mmx(u_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_horizontal_edge_mmx(v_ptr + 4 * uv_stride, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + + +void vp8_loop_filter_bhs_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 4 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 8 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_horizontal_edge_sse2(y_ptr + 12 * y_stride, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + + +// Vertical B Filtering +void vp8_loop_filter_bv_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) simpler_lpf; + vp8_loop_filter_vertical_edge_sse2(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_sse2(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_vertical_edge_sse2(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + + if (u_ptr) + vp8_loop_filter_vertical_edge_mmx(u_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); + + if (v_ptr) + vp8_loop_filter_vertical_edge_mmx(v_ptr + 4, uv_stride, lfi->uvflim, lfi->uvlim, lfi->uvthr, 1); +} + + +void vp8_loop_filter_bvs_sse2(unsigned char *y_ptr, unsigned char *u_ptr, unsigned char *v_ptr, + int y_stride, int uv_stride, loop_filter_info *lfi, int simpler_lpf) +{ + (void) u_ptr; + (void) v_ptr; + (void) uv_stride; + (void) simpler_lpf; + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} + +#endif + +#if 0 +void vp8_fast_loop_filter_vertical_edges_sse(unsigned char *y_ptr, + int y_stride, + loop_filter_info *lfi) +{ + + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 4, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 8, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); + vp8_loop_filter_simple_vertical_edge_sse2(y_ptr + 12, y_stride, lfi->flim, lfi->lim, lfi->thr, 2); +} +#endif
diff --git a/vp8/common/x86/loopfilter_x86.h b/vp8/common/x86/loopfilter_x86.h new file mode 100644 index 0000000..c87f38a --- /dev/null +++ b/vp8/common/x86/loopfilter_x86.h
@@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef LOOPFILTER_X86_H +#define LOOPFILTER_X86_H + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ + +#if HAVE_MMX +extern prototype_loopfilter_block(vp8_loop_filter_mbv_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_bv_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_mbh_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_bh_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_mbvs_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_bvs_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_mbhs_mmx); +extern prototype_loopfilter_block(vp8_loop_filter_bhs_mmx); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_lf_normal_mb_v +#define vp8_lf_normal_mb_v vp8_loop_filter_mbv_mmx + +#undef vp8_lf_normal_b_v +#define vp8_lf_normal_b_v vp8_loop_filter_bv_mmx + +#undef vp8_lf_normal_mb_h +#define vp8_lf_normal_mb_h vp8_loop_filter_mbh_mmx + +#undef vp8_lf_normal_b_h +#define vp8_lf_normal_b_h vp8_loop_filter_bh_mmx + +#undef vp8_lf_simple_mb_v +#define vp8_lf_simple_mb_v vp8_loop_filter_mbvs_mmx + +#undef vp8_lf_simple_b_v +#define vp8_lf_simple_b_v vp8_loop_filter_bvs_mmx + +#undef vp8_lf_simple_mb_h +#define vp8_lf_simple_mb_h vp8_loop_filter_mbhs_mmx + +#undef vp8_lf_simple_b_h +#define vp8_lf_simple_b_h vp8_loop_filter_bhs_mmx +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_loopfilter_block(vp8_loop_filter_mbv_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_bv_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_mbh_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_bh_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_mbvs_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_bvs_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_mbhs_sse2); +extern prototype_loopfilter_block(vp8_loop_filter_bhs_sse2); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_lf_normal_mb_v +#define vp8_lf_normal_mb_v vp8_loop_filter_mbv_sse2 + +#undef vp8_lf_normal_b_v +#define vp8_lf_normal_b_v vp8_loop_filter_bv_sse2 + +#undef vp8_lf_normal_mb_h +#define vp8_lf_normal_mb_h vp8_loop_filter_mbh_sse2 + +#undef vp8_lf_normal_b_h +#define vp8_lf_normal_b_h vp8_loop_filter_bh_sse2 + +#undef vp8_lf_simple_mb_v +#define vp8_lf_simple_mb_v vp8_loop_filter_mbvs_sse2 + +#undef vp8_lf_simple_b_v +#define vp8_lf_simple_b_v vp8_loop_filter_bvs_sse2 + +#undef vp8_lf_simple_mb_h +#define vp8_lf_simple_mb_h vp8_loop_filter_mbhs_sse2 + +#undef vp8_lf_simple_b_h +#define vp8_lf_simple_b_h vp8_loop_filter_bhs_sse2 +#endif +#endif + + +#endif
diff --git a/vp8/common/x86/postproc_mmx.asm b/vp8/common/x86/postproc_mmx.asm new file mode 100644 index 0000000..721c8d6 --- /dev/null +++ b/vp8/common/x86/postproc_mmx.asm
@@ -0,0 +1,533 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define VP8_FILTER_WEIGHT 128 +%define VP8_FILTER_SHIFT 7 + +;void vp8_post_proc_down_and_across_mmx +;( +; unsigned char *src_ptr, +; unsigned char *dst_ptr, +; int src_pixels_per_line, +; int dst_pixels_per_line, +; int rows, +; int cols, +; int flimit +;) +global sym(vp8_post_proc_down_and_across_mmx) +sym(vp8_post_proc_down_and_across_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + ; move the global rd onto the stack, since we don't have enough registers + ; to do PIC addressing + movq mm0, [rd GLOBAL] + sub rsp, 8 + movq [rsp], mm0 +%define RD [rsp] +%else +%define RD [rd GLOBAL] +%endif + + push rbx + lea rbx, [Blur GLOBAL] + movd mm2, dword ptr arg(6) ;flimit + punpcklwd mm2, mm2 + punpckldq mm2, mm2 + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;dst_ptr + + movsxd rcx, DWORD PTR arg(4) ;rows + movsxd rax, DWORD PTR arg(2) ;src_pixels_per_line ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + +nextrow: + + xor rdx, rdx ; clear out rdx for use as loop counter +nextcol: + + pxor mm7, mm7 ; mm7 = 00000000 + movq mm6, [rbx + 32 ] ; mm6 = kernel 2 taps + movq mm3, [rsi] ; mm4 = r0 p0..p7 + punpcklbw mm3, mm0 ; mm3 = p0..p3 + movq mm1, mm3 ; mm1 = p0..p3 + pmullw mm3, mm6 ; mm3 *= kernel 2 modifiers + + movq mm6, [rbx + 48] ; mm6 = kernel 3 taps + movq mm5, [rsi + rax] ; mm4 = r1 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r1 p0..p3 + pmullw mm6, mm5 ; mm6 *= p0..p3 * kernel 3 modifiers + paddusw mm3, mm6 ; mm3 += mm6 + + ; thresholding + movq mm7, mm1 ; mm7 = r0 p0..p3 + psubusw mm7, mm5 ; mm7 = r0 p0..p3 - r1 p0..p3 + psubusw mm5, mm1 ; mm5 = r1 p0..p3 - r0 p0..p3 + paddusw mm7, mm5 ; mm7 = abs(r0 p0..p3 - r1 p0..p3) + pcmpgtw mm7, mm2 + + movq mm6, [rbx + 64 ] ; mm6 = kernel 4 modifiers + movq mm5, [rsi + 2*rax] ; mm4 = r2 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r2 p0..p3 + pmullw mm6, mm5 ; mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm5 ; mm6 = r0 p0..p3 - r2 p0..p3 + psubusw mm5, mm1 ; mm5 = r2 p0..p3 - r2 p0..p3 + paddusw mm6, mm5 ; mm6 = abs(r0 p0..p3 - r2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + neg rax + movq mm6, [rbx ] ; kernel 0 taps + movq mm5, [rsi+2*rax] ; mm4 = r-2 p0..p7 + punpcklbw mm5, mm0 ; mm5 = r-2 p0..p3 + pmullw mm6, mm5 ; mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw mm5, mm1 ; mm5 = r-2 p0..p3 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(r0 p0..p3 - r-2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + movq mm6, [rbx + 16] ; kernel 1 taps + movq mm4, [rsi+rax] ; mm4 = r-1 p0..p7 + punpcklbw mm4, mm0 ; mm4 = r-1 p0..p3 + pmullw mm6, mm4 ; mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = r0 p0..p3 + psubusw mm6, mm4 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw mm4, mm1 ; mm5 = r-1 p0..p3 - p0..p3 + paddusw mm6, mm4 ; mm6 = abs(r0 p0..p3 - r-1 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + paddusw mm3, RD ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + + pand mm1, mm7 ; mm1 select vals > thresh from source + pandn mm7, mm3 ; mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; combination + + packuswb mm1, mm0 ; pack to bytes + + movd [rdi], mm1 ; + neg rax ; pitch is positive + + + add rsi, 4 + add rdi, 4 + add rdx, 4 + + cmp edx, dword ptr arg(5) ;cols + jl nextcol + ; done with the all cols, start the across filtering in place + sub rsi, rdx + sub rdi, rdx + + + push rax + xor rdx, rdx + mov rax, [rdi-4]; + +acrossnextcol: + pxor mm7, mm7 ; mm7 = 00000000 + movq mm6, [rbx + 32 ] ; + movq mm4, [rdi+rdx] ; mm4 = p0..p7 + movq mm3, mm4 ; mm3 = p0..p7 + punpcklbw mm3, mm0 ; mm3 = p0..p3 + movq mm1, mm3 ; mm1 = p0..p3 + pmullw mm3, mm6 ; mm3 *= kernel 2 modifiers + + movq mm6, [rbx + 48] + psrlq mm4, 8 ; mm4 = p1..p7 + movq mm5, mm4 ; mm5 = p1..p7 + punpcklbw mm5, mm0 ; mm5 = p1..p4 + pmullw mm6, mm5 ; mm6 *= p1..p4 * kernel 3 modifiers + paddusw mm3, mm6 ; mm3 += mm6 + + ; thresholding + movq mm7, mm1 ; mm7 = p0..p3 + psubusw mm7, mm5 ; mm7 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm7, mm5 ; mm7 = abs(p0..p3 - p1..p4) + pcmpgtw mm7, mm2 + + movq mm6, [rbx + 64 ] + psrlq mm4, 8 ; mm4 = p2..p7 + movq mm5, mm4 ; mm5 = p2..p7 + punpcklbw mm5, mm0 ; mm5 = p2..p5 + pmullw mm6, mm5 ; mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + + movq mm6, [rbx ] + movq mm4, [rdi+rdx-2] ; mm4 = p-2..p5 + movq mm5, mm4 ; mm5 = p-2..p5 + punpcklbw mm5, mm0 ; mm5 = p-2..p1 + pmullw mm6, mm5 ; mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm5 ; mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + movq mm6, [rbx + 16] + psrlq mm4, 8 ; mm4 = p-1..p5 + punpcklbw mm4, mm0 ; mm4 = p-1..p2 + pmullw mm6, mm4 ; mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; mm3 += mm5 + + ; thresholding + movq mm6, mm1 ; mm6 = p0..p3 + psubusw mm6, mm4 ; mm6 = p0..p3 - p1..p4 + psubusw mm4, mm1 ; mm5 = p1..p4 - p0..p3 + paddusw mm6, mm4 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; accumulate thresholds + + paddusw mm3, RD ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + + pand mm1, mm7 ; mm1 select vals > thresh from source + pandn mm7, mm3 ; mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; combination + + packuswb mm1, mm0 ; pack to bytes + mov DWORD PTR [rdi+rdx-4], eax ; store previous four bytes + movd eax, mm1 + + add rdx, 4 + cmp edx, dword ptr arg(5) ;cols + jl acrossnextcol; + + mov DWORD PTR [rdi+rdx-4], eax + pop rax + + ; done with this rwo + add rsi,rax ; next line + movsxd rax, dword ptr arg(3) ;dst_pixels_per_line ; destination pitch? + add rdi,rax ; next destination + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; destination pitch? + + dec rcx ; decrement count + jnz nextrow ; next row + pop rbx + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef RD + + +;void vp8_mbpost_proc_down_mmx(unsigned char *dst, +; int pitch, int rows, int cols,int flimit) +extern sym(vp8_rv) +global sym(vp8_mbpost_proc_down_mmx) +sym(vp8_mbpost_proc_down_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 136 + + ; unsigned char d[16][8] at [rsp] + ; create flimit2 at [rsp+128] + mov eax, dword ptr arg(4) ;flimit + mov [rsp+128], eax + mov [rsp+128+4], eax +%define flimit2 [rsp+128] + +%if ABI_IS_32BIT=0 + lea r8, [sym(vp8_rv) GLOBAL] +%endif + + ;rows +=8; + add dword ptr arg(2), 8 + + ;for(c=0; c<cols; c+=4) +loop_col: + mov rsi, arg(0) ;s + pxor mm0, mm0 ; + + movsxd rax, dword ptr arg(1) ;pitch ; + neg rax ; rax = -pitch + + lea rsi, [rsi + rax*8]; ; rdi = s[-pitch*8] + neg rax + + + pxor mm5, mm5 + pxor mm6, mm6 ; + + pxor mm7, mm7 ; + mov rdi, rsi + + mov rcx, 15 ; + +loop_initvar: + movd mm1, DWORD PTR [rdi]; + punpcklbw mm1, mm0 ; + + paddw mm5, mm1 ; + pmullw mm1, mm1 ; + + movq mm2, mm1 ; + punpcklwd mm1, mm0 ; + + punpckhwd mm2, mm0 ; + paddd mm6, mm1 ; + + paddd mm7, mm2 ; + lea rdi, [rdi+rax] ; + + dec rcx + jne loop_initvar + ;save the var and sum + xor rdx, rdx +loop_row: + movd mm1, DWORD PTR [rsi] ; [s-pitch*8] + movd mm2, DWORD PTR [rdi] ; [s+pitch*7] + + punpcklbw mm1, mm0 + punpcklbw mm2, mm0 + + paddw mm5, mm2 + psubw mm5, mm1 + + pmullw mm2, mm2 + movq mm4, mm2 + + punpcklwd mm2, mm0 + punpckhwd mm4, mm0 + + paddd mm6, mm2 + paddd mm7, mm4 + + pmullw mm1, mm1 + movq mm2, mm1 + + punpcklwd mm1, mm0 + psubd mm6, mm1 + + punpckhwd mm2, mm0 + psubd mm7, mm2 + + + movq mm3, mm6 + pslld mm3, 4 + + psubd mm3, mm6 + movq mm1, mm5 + + movq mm4, mm5 + pmullw mm1, mm1 + + pmulhw mm4, mm4 + movq mm2, mm1 + + punpcklwd mm1, mm4 + punpckhwd mm2, mm4 + + movq mm4, mm7 + pslld mm4, 4 + + psubd mm4, mm7 + + psubd mm3, mm1 + psubd mm4, mm2 + + psubd mm3, flimit2 + psubd mm4, flimit2 + + psrad mm3, 31 + psrad mm4, 31 + + packssdw mm3, mm4 + packsswb mm3, mm0 + + movd mm1, DWORD PTR [rsi+rax*8] + + movq mm2, mm1 + punpcklbw mm1, mm0 + + paddw mm1, mm5 + mov rcx, rdx + + and rcx, 127 +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + push rax + lea rax, [sym(vp8_rv) GLOBAL] + movq mm4, [rax + rcx*2] ;vp8_rv[rcx*2] + pop rax +%elif ABI_IS_32BIT=0 + movq mm4, [r8 + rcx*2] ;vp8_rv[rcx*2] +%else + movq mm4, [sym(vp8_rv) + rcx*2] +%endif + paddw mm1, mm4 + ;paddw xmm1, eight8s + psraw mm1, 4 + + packuswb mm1, mm0 + pand mm1, mm3 + + pandn mm3, mm2 + por mm1, mm3 + + and rcx, 15 + movd DWORD PTR [rsp+rcx*4], mm1 ;d[rcx*4] + + mov rcx, rdx + sub rcx, 8 + + and rcx, 15 + movd mm1, DWORD PTR [rsp+rcx*4] ;d[rcx*4] + + movd [rsi], mm1 + lea rsi, [rsi+rax] + + lea rdi, [rdi+rax] + add rdx, 1 + + cmp edx, dword arg(2) ;rows + jl loop_row + + + add dword arg(0), 4 ; s += 4 + sub dword arg(3), 4 ; cols -= 4 + cmp dword arg(3), 0 + jg loop_col + + add rsp, 136 + pop rsp + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef flimit2 + + +;void vp8_plane_add_noise_mmx (unsigned char *Start, unsigned char *noise, +; unsigned char blackclamp[16], +; unsigned char whiteclamp[16], +; unsigned char bothclamp[16], +; unsigned int Width, unsigned int Height, int Pitch) +extern sym(rand) +global sym(vp8_plane_add_noise_mmx) +sym(vp8_plane_add_noise_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +addnoise_loop: + call sym(rand) WRT_PLT + mov rcx, arg(1) ;noise + and rax, 0xff + add rcx, rax + + ; we rely on the fact that the clamping vectors are stored contiguously + ; in black/white/both order. Note that we have to reload this here because + ; rdx could be trashed by rand() + mov rdx, arg(2) ; blackclamp + + + mov rdi, rcx + movsxd rcx, dword arg(5) ;[Width] + mov rsi, arg(0) ;Pos + xor rax,rax + +addnoise_nextset: + movq mm1,[rsi+rax] ; get the source + + psubusb mm1, [rdx] ;blackclamp ; clamp both sides so we don't outrange adding noise + paddusb mm1, [rdx+32] ;bothclamp + psubusb mm1, [rdx+16] ;whiteclamp + + movq mm2,[rdi+rax] ; get the noise for this line + paddb mm1,mm2 ; add it in + movq [rsi+rax],mm1 ; store the result + + add rax,8 ; move to the next line + + cmp rax, rcx + jl addnoise_nextset + + movsxd rax, dword arg(7) ; Pitch + add arg(0), rax ; Start += Pitch + sub dword arg(6), 1 ; Height -= 1 + jg addnoise_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +Blur: + times 16 dw 16 + times 8 dw 64 + times 16 dw 16 + times 8 dw 0 + +rd: + times 4 dw 0x40
diff --git a/vp8/common/x86/postproc_mmx.c b/vp8/common/x86/postproc_mmx.c new file mode 100644 index 0000000..095797b --- /dev/null +++ b/vp8/common/x86/postproc_mmx.c
@@ -0,0 +1,1507 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> +#include <stdlib.h> +#include "vpx_scale/yv12config.h" +#include "pragmas.h" + +#define VP8_FILTER_WEIGHT 128 +#define VP8_FILTER_SHIFT 7 + + + +/* static constants */ +__declspec(align(16)) +const static short Blur[48] = +{ + + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 64, 64, 64, 64, 64, 64, 64, 64, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + +}; +#define RD __declspec(align(16)) __int64 rd = 0x0040004000400040; +#define R4D2 __declspec(align(16)) __int64 rd42[2] = {0x0004000400040004,0x0004000400040004}; + +#ifndef RELOCATEABLE +const static RD; +const static R4D2; +#endif + + +/* external references */ +extern double vp8_gaussian(double sigma, double mu, double x); +extern short vp8_rv[]; +extern int vp8_q2mbl(int x) ; + + + +void vp8_post_proc_down_and_across_mmx +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +) +{ +#ifdef RELOCATEABLE + RD + R4D2 +#endif + + __asm + { + push ebx + lea ebx, Blur + movd mm2, flimit + punpcklwd mm2, mm2 + punpckldq mm2, mm2 + + mov esi, src_ptr + mov edi, dst_ptr + + mov ecx, DWORD PTR rows + mov eax, src_pixels_per_line ; + destination pitch? + pxor mm0, mm0 ; + mm0 = 00000000 + + nextrow: + + xor edx, edx ; + + clear out edx for use as loop counter + nextcol: + + pxor mm7, mm7 ; + + mm7 = 00000000 + movq mm6, [ebx + 32 ] ; + mm6 = kernel 2 taps + movq mm3, [esi] ; + mm4 = r0 p0..p7 + punpcklbw mm3, mm0 ; + mm3 = p0..p3 + movq mm1, mm3 ; + mm1 = p0..p3 + pmullw mm3, mm6 ; + mm3 *= kernel 2 modifiers + + movq mm6, [ebx + 48] ; + mm6 = kernel 3 taps + movq mm5, [esi + eax] ; + mm4 = r1 p0..p7 + punpcklbw mm5, mm0 ; + mm5 = r1 p0..p3 + pmullw mm6, mm5 ; + mm6 *= p0..p3 * kernel 3 modifiers + paddusw mm3, mm6 ; + mm3 += mm6 + + ; + thresholding + movq mm7, mm1 ; + mm7 = r0 p0..p3 + psubusw mm7, mm5 ; + mm7 = r0 p0..p3 - r1 p0..p3 + psubusw mm5, mm1 ; + mm5 = r1 p0..p3 - r0 p0..p3 + paddusw mm7, mm5 ; + mm7 = abs(r0 p0..p3 - r1 p0..p3) + pcmpgtw mm7, mm2 + + movq mm6, [ebx + 64 ] ; + mm6 = kernel 4 modifiers + movq mm5, [esi + 2*eax] ; + mm4 = r2 p0..p7 + punpcklbw mm5, mm0 ; + mm5 = r2 p0..p3 + pmullw mm6, mm5 ; + mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = r0 p0..p3 + psubusw mm6, mm5 ; + mm6 = r0 p0..p3 - r2 p0..p3 + psubusw mm5, mm1 ; + mm5 = r2 p0..p3 - r2 p0..p3 + paddusw mm6, mm5 ; + mm6 = abs(r0 p0..p3 - r2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + + neg eax + movq mm6, [ebx ] ; + kernel 0 taps + movq mm5, [esi+2*eax] ; + mm4 = r-2 p0..p7 + punpcklbw mm5, mm0 ; + mm5 = r-2 p0..p3 + pmullw mm6, mm5 ; + mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = r0 p0..p3 + psubusw mm6, mm5 ; + mm6 = p0..p3 - r-2 p0..p3 + psubusw mm5, mm1 ; + mm5 = r-2 p0..p3 - p0..p3 + paddusw mm6, mm5 ; + mm6 = abs(r0 p0..p3 - r-2 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + movq mm6, [ebx + 16] ; + kernel 1 taps + movq mm4, [esi+eax] ; + mm4 = r-1 p0..p7 + punpcklbw mm4, mm0 ; + mm4 = r-1 p0..p3 + pmullw mm6, mm4 ; + mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = r0 p0..p3 + psubusw mm6, mm4 ; + mm6 = p0..p3 - r-2 p0..p3 + psubusw mm4, mm1 ; + mm5 = r-1 p0..p3 - p0..p3 + paddusw mm6, mm4 ; + mm6 = abs(r0 p0..p3 - r-1 p0..p3) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + + paddusw mm3, rd ; + mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; + mm3 /= 128 + + pand mm1, mm7 ; + mm1 select vals > thresh from source + pandn mm7, mm3 ; + mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; + combination + + packuswb mm1, mm0 ; + pack to bytes + + movd [edi], mm1 ; + neg eax ; + pitch is positive + + + add esi, 4 + add edi, 4 + add edx, 4 + + cmp edx, cols + jl nextcol + // done with the all cols, start the across filtering in place + sub esi, edx + sub edi, edx + + + push eax + xor edx, edx + mov eax, [edi-4]; + + acrossnextcol: + pxor mm7, mm7 ; + mm7 = 00000000 + movq mm6, [ebx + 32 ] ; + movq mm4, [edi+edx] ; + mm4 = p0..p7 + movq mm3, mm4 ; + mm3 = p0..p7 + punpcklbw mm3, mm0 ; + mm3 = p0..p3 + movq mm1, mm3 ; + mm1 = p0..p3 + pmullw mm3, mm6 ; + mm3 *= kernel 2 modifiers + + movq mm6, [ebx + 48] + psrlq mm4, 8 ; + mm4 = p1..p7 + movq mm5, mm4 ; + mm5 = p1..p7 + punpcklbw mm5, mm0 ; + mm5 = p1..p4 + pmullw mm6, mm5 ; + mm6 *= p1..p4 * kernel 3 modifiers + paddusw mm3, mm6 ; + mm3 += mm6 + + ; + thresholding + movq mm7, mm1 ; + mm7 = p0..p3 + psubusw mm7, mm5 ; + mm7 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; + mm5 = p1..p4 - p0..p3 + paddusw mm7, mm5 ; + mm7 = abs(p0..p3 - p1..p4) + pcmpgtw mm7, mm2 + + movq mm6, [ebx + 64 ] + psrlq mm4, 8 ; + mm4 = p2..p7 + movq mm5, mm4 ; + mm5 = p2..p7 + punpcklbw mm5, mm0 ; + mm5 = p2..p5 + pmullw mm6, mm5 ; + mm5 *= kernel 4 modifiers + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = p0..p3 + psubusw mm6, mm5 ; + mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; + mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + + movq mm6, [ebx ] + movq mm4, [edi+edx-2] ; + mm4 = p-2..p5 + movq mm5, mm4 ; + mm5 = p-2..p5 + punpcklbw mm5, mm0 ; + mm5 = p-2..p1 + pmullw mm6, mm5 ; + mm5 *= kernel 0 modifiers + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = p0..p3 + psubusw mm6, mm5 ; + mm6 = p0..p3 - p1..p4 + psubusw mm5, mm1 ; + mm5 = p1..p4 - p0..p3 + paddusw mm6, mm5 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + movq mm6, [ebx + 16] + psrlq mm4, 8 ; + mm4 = p-1..p5 + punpcklbw mm4, mm0 ; + mm4 = p-1..p2 + pmullw mm6, mm4 ; + mm4 *= kernel 1 modifiers. + paddusw mm3, mm6 ; + mm3 += mm5 + + ; + thresholding + movq mm6, mm1 ; + mm6 = p0..p3 + psubusw mm6, mm4 ; + mm6 = p0..p3 - p1..p4 + psubusw mm4, mm1 ; + mm5 = p1..p4 - p0..p3 + paddusw mm6, mm4 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw mm6, mm2 + por mm7, mm6 ; + accumulate thresholds + + paddusw mm3, rd ; + mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; + mm3 /= 128 + + pand mm1, mm7 ; + mm1 select vals > thresh from source + pandn mm7, mm3 ; + mm7 select vals < thresh from blurred result + paddusw mm1, mm7 ; + combination + + packuswb mm1, mm0 ; + pack to bytes + mov DWORD PTR [edi+edx-4], eax ; + store previous four bytes + movd eax, mm1 + + add edx, 4 + cmp edx, cols + jl acrossnextcol; + + mov DWORD PTR [edi+edx-4], eax + pop eax + + // done with this rwo + add esi, eax ; + next line + mov eax, dst_pixels_per_line ; + destination pitch? + add edi, eax ; + next destination + mov eax, src_pixels_per_line ; + destination pitch? + + dec ecx ; + decrement count + jnz nextrow ; + next row + pop ebx + + } +} + + + +void vp8_post_proc_down_and_across_xmm +( + unsigned char *src_ptr, + unsigned char *dst_ptr, + int src_pixels_per_line, + int dst_pixels_per_line, + int rows, + int cols, + int flimit +) +{ +#ifdef RELOCATEABLE + R4D2 +#endif + + __asm + { + movd xmm2, flimit + punpcklwd xmm2, xmm2 + punpckldq xmm2, xmm2 + punpcklqdq xmm2, xmm2 + + mov esi, src_ptr + mov edi, dst_ptr + + mov ecx, DWORD PTR rows + mov eax, src_pixels_per_line ; + destination pitch? + pxor xmm0, xmm0 ; + mm0 = 00000000 + + nextrow: + + xor edx, edx ; + + clear out edx for use as loop counter + nextcol: + movq xmm3, QWORD PTR [esi] ; + + mm4 = r0 p0..p7 + punpcklbw xmm3, xmm0 ; + mm3 = p0..p3 + movdqa xmm1, xmm3 ; + mm1 = p0..p3 + psllw xmm3, 2 ; + + movq xmm5, QWORD PTR [esi + eax] ; + mm4 = r1 p0..p7 + punpcklbw xmm5, xmm0 ; + mm5 = r1 p0..p3 + paddusw xmm3, xmm5 ; + mm3 += mm6 + + ; + thresholding + movdqa xmm7, xmm1 ; + mm7 = r0 p0..p3 + psubusw xmm7, xmm5 ; + mm7 = r0 p0..p3 - r1 p0..p3 + psubusw xmm5, xmm1 ; + mm5 = r1 p0..p3 - r0 p0..p3 + paddusw xmm7, xmm5 ; + mm7 = abs(r0 p0..p3 - r1 p0..p3) + pcmpgtw xmm7, xmm2 + + movq xmm5, QWORD PTR [esi + 2*eax] ; + mm4 = r2 p0..p7 + punpcklbw xmm5, xmm0 ; + mm5 = r2 p0..p3 + paddusw xmm3, xmm5 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = r0 p0..p3 + psubusw xmm6, xmm5 ; + mm6 = r0 p0..p3 - r2 p0..p3 + psubusw xmm5, xmm1 ; + mm5 = r2 p0..p3 - r2 p0..p3 + paddusw xmm6, xmm5 ; + mm6 = abs(r0 p0..p3 - r2 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + + neg eax + movq xmm5, QWORD PTR [esi+2*eax] ; + mm4 = r-2 p0..p7 + punpcklbw xmm5, xmm0 ; + mm5 = r-2 p0..p3 + paddusw xmm3, xmm5 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = r0 p0..p3 + psubusw xmm6, xmm5 ; + mm6 = p0..p3 - r-2 p0..p3 + psubusw xmm5, xmm1 ; + mm5 = r-2 p0..p3 - p0..p3 + paddusw xmm6, xmm5 ; + mm6 = abs(r0 p0..p3 - r-2 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + movq xmm4, QWORD PTR [esi+eax] ; + mm4 = r-1 p0..p7 + punpcklbw xmm4, xmm0 ; + mm4 = r-1 p0..p3 + paddusw xmm3, xmm4 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = r0 p0..p3 + psubusw xmm6, xmm4 ; + mm6 = p0..p3 - r-2 p0..p3 + psubusw xmm4, xmm1 ; + mm5 = r-1 p0..p3 - p0..p3 + paddusw xmm6, xmm4 ; + mm6 = abs(r0 p0..p3 - r-1 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + + paddusw xmm3, rd42 ; + mm3 += round value + psraw xmm3, 3 ; + mm3 /= 8 + + pand xmm1, xmm7 ; + mm1 select vals > thresh from source + pandn xmm7, xmm3 ; + mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; + combination + + packuswb xmm1, xmm0 ; + pack to bytes + movq QWORD PTR [edi], xmm1 ; + + neg eax ; + pitch is positive + add esi, 8 + add edi, 8 + + add edx, 8 + cmp edx, cols + + jl nextcol + + // done with the all cols, start the across filtering in place + sub esi, edx + sub edi, edx + + xor edx, edx + movq mm0, QWORD PTR [edi-8]; + + acrossnextcol: + movq xmm7, QWORD PTR [edi +edx -2] + movd xmm4, DWORD PTR [edi +edx +6] + + pslldq xmm4, 8 + por xmm4, xmm7 + + movdqa xmm3, xmm4 + psrldq xmm3, 2 + punpcklbw xmm3, xmm0 ; + mm3 = p0..p3 + movdqa xmm1, xmm3 ; + mm1 = p0..p3 + psllw xmm3, 2 + + + movdqa xmm5, xmm4 + psrldq xmm5, 3 + punpcklbw xmm5, xmm0 ; + mm5 = p1..p4 + paddusw xmm3, xmm5 ; + mm3 += mm6 + + ; + thresholding + movdqa xmm7, xmm1 ; + mm7 = p0..p3 + psubusw xmm7, xmm5 ; + mm7 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; + mm5 = p1..p4 - p0..p3 + paddusw xmm7, xmm5 ; + mm7 = abs(p0..p3 - p1..p4) + pcmpgtw xmm7, xmm2 + + movdqa xmm5, xmm4 + psrldq xmm5, 4 + punpcklbw xmm5, xmm0 ; + mm5 = p2..p5 + paddusw xmm3, xmm5 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = p0..p3 + psubusw xmm6, xmm5 ; + mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; + mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + + movdqa xmm5, xmm4 ; + mm5 = p-2..p5 + punpcklbw xmm5, xmm0 ; + mm5 = p-2..p1 + paddusw xmm3, xmm5 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = p0..p3 + psubusw xmm6, xmm5 ; + mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; + mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + psrldq xmm4, 1 ; + mm4 = p-1..p5 + punpcklbw xmm4, xmm0 ; + mm4 = p-1..p2 + paddusw xmm3, xmm4 ; + mm3 += mm5 + + ; + thresholding + movdqa xmm6, xmm1 ; + mm6 = p0..p3 + psubusw xmm6, xmm4 ; + mm6 = p0..p3 - p1..p4 + psubusw xmm4, xmm1 ; + mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm4 ; + mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; + accumulate thresholds + + paddusw xmm3, rd42 ; + mm3 += round value + psraw xmm3, 3 ; + mm3 /= 8 + + pand xmm1, xmm7 ; + mm1 select vals > thresh from source + pandn xmm7, xmm3 ; + mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; + combination + + packuswb xmm1, xmm0 ; + pack to bytes + movq QWORD PTR [edi+edx-8], mm0 ; + store previous four bytes + movdq2q mm0, xmm1 + + add edx, 8 + cmp edx, cols + jl acrossnextcol; + + // last 8 pixels + movq QWORD PTR [edi+edx-8], mm0 + + // done with this rwo + add esi, eax ; + next line + mov eax, dst_pixels_per_line ; + destination pitch? + add edi, eax ; + next destination + mov eax, src_pixels_per_line ; + destination pitch? + + dec ecx ; + decrement count + jnz nextrow ; + next row + } +} + + +void vp8_mbpost_proc_down_mmx(unsigned char *dst, int pitch, int rows, int cols, int flimit) +{ + int c, i; + __declspec(align(16)) + int flimit2[2]; + __declspec(align(16)) + unsigned char d[16][8]; + + flimit = vp8_q2mbl(flimit); + + for (i = 0; i < 2; i++) + flimit2[i] = flimit; + + rows += 8; + + for (c = 0; c < cols; c += 4) + { + unsigned char *s = &dst[c]; + + __asm + { + mov esi, s ; + pxor mm0, mm0 ; + + mov eax, pitch ; + neg eax // eax = -pitch + + lea esi, [esi + eax*8]; // edi = s[-pitch*8] + neg eax + + + pxor mm5, mm5 + pxor mm6, mm6 ; + + pxor mm7, mm7 ; + mov edi, esi + + mov ecx, 15 ; + + loop_initvar: + movd mm1, DWORD PTR [edi]; + punpcklbw mm1, mm0 ; + + paddw mm5, mm1 ; + pmullw mm1, mm1 ; + + movq mm2, mm1 ; + punpcklwd mm1, mm0 ; + + punpckhwd mm2, mm0 ; + paddd mm6, mm1 ; + + paddd mm7, mm2 ; + lea edi, [edi+eax] ; + + dec ecx + jne loop_initvar + //save the var and sum + xor edx, edx + loop_row: + movd mm1, DWORD PTR [esi] // [s-pitch*8] + movd mm2, DWORD PTR [edi] // [s+pitch*7] + + punpcklbw mm1, mm0 + punpcklbw mm2, mm0 + + paddw mm5, mm2 + psubw mm5, mm1 + + pmullw mm2, mm2 + movq mm4, mm2 + + punpcklwd mm2, mm0 + punpckhwd mm4, mm0 + + paddd mm6, mm2 + paddd mm7, mm4 + + pmullw mm1, mm1 + movq mm2, mm1 + + punpcklwd mm1, mm0 + psubd mm6, mm1 + + punpckhwd mm2, mm0 + psubd mm7, mm2 + + + movq mm3, mm6 + pslld mm3, 4 + + psubd mm3, mm6 + movq mm1, mm5 + + movq mm4, mm5 + pmullw mm1, mm1 + + pmulhw mm4, mm4 + movq mm2, mm1 + + punpcklwd mm1, mm4 + punpckhwd mm2, mm4 + + movq mm4, mm7 + pslld mm4, 4 + + psubd mm4, mm7 + + psubd mm3, mm1 + psubd mm4, mm2 + + psubd mm3, flimit2 + psubd mm4, flimit2 + + psrad mm3, 31 + psrad mm4, 31 + + packssdw mm3, mm4 + packsswb mm3, mm0 + + movd mm1, DWORD PTR [esi+eax*8] + + movq mm2, mm1 + punpcklbw mm1, mm0 + + paddw mm1, mm5 + mov ecx, edx + + and ecx, 127 + movq mm4, vp8_rv[ecx*2] + + paddw mm1, mm4 + //paddw xmm1, eight8s + psraw mm1, 4 + + packuswb mm1, mm0 + pand mm1, mm3 + + pandn mm3, mm2 + por mm1, mm3 + + and ecx, 15 + movd DWORD PTR d[ecx*4], mm1 + + mov ecx, edx + sub ecx, 8 + + and ecx, 15 + movd mm1, DWORD PTR d[ecx*4] + + movd [esi], mm1 + lea esi, [esi+eax] + + lea edi, [edi+eax] + add edx, 1 + + cmp edx, rows + jl loop_row + + } + + } +} + +void vp8_mbpost_proc_down_xmm(unsigned char *dst, int pitch, int rows, int cols, int flimit) +{ + int c, i; + __declspec(align(16)) + int flimit4[4]; + __declspec(align(16)) + unsigned char d[16][8]; + + flimit = vp8_q2mbl(flimit); + + for (i = 0; i < 4; i++) + flimit4[i] = flimit; + + rows += 8; + + for (c = 0; c < cols; c += 8) + { + unsigned char *s = &dst[c]; + + __asm + { + mov esi, s ; + pxor xmm0, xmm0 ; + + mov eax, pitch ; + neg eax // eax = -pitch + + lea esi, [esi + eax*8]; // edi = s[-pitch*8] + neg eax + + + pxor xmm5, xmm5 + pxor xmm6, xmm6 ; + + pxor xmm7, xmm7 ; + mov edi, esi + + mov ecx, 15 ; + + loop_initvar: + movq xmm1, QWORD PTR [edi]; + punpcklbw xmm1, xmm0 ; + + paddw xmm5, xmm1 ; + pmullw xmm1, xmm1 ; + + movdqa xmm2, xmm1 ; + punpcklwd xmm1, xmm0 ; + + punpckhwd xmm2, xmm0 ; + paddd xmm6, xmm1 ; + + paddd xmm7, xmm2 ; + lea edi, [edi+eax] ; + + dec ecx + jne loop_initvar + //save the var and sum + xor edx, edx + loop_row: + movq xmm1, QWORD PTR [esi] // [s-pitch*8] + movq xmm2, QWORD PTR [edi] // [s+pitch*7] + + punpcklbw xmm1, xmm0 + punpcklbw xmm2, xmm0 + + paddw xmm5, xmm2 + psubw xmm5, xmm1 + + pmullw xmm2, xmm2 + movdqa xmm4, xmm2 + + punpcklwd xmm2, xmm0 + punpckhwd xmm4, xmm0 + + paddd xmm6, xmm2 + paddd xmm7, xmm4 + + pmullw xmm1, xmm1 + movdqa xmm2, xmm1 + + punpcklwd xmm1, xmm0 + psubd xmm6, xmm1 + + punpckhwd xmm2, xmm0 + psubd xmm7, xmm2 + + + movdqa xmm3, xmm6 + pslld xmm3, 4 + + psubd xmm3, xmm6 + movdqa xmm1, xmm5 + + movdqa xmm4, xmm5 + pmullw xmm1, xmm1 + + pmulhw xmm4, xmm4 + movdqa xmm2, xmm1 + + punpcklwd xmm1, xmm4 + punpckhwd xmm2, xmm4 + + movdqa xmm4, xmm7 + pslld xmm4, 4 + + psubd xmm4, xmm7 + + psubd xmm3, xmm1 + psubd xmm4, xmm2 + + psubd xmm3, flimit4 + psubd xmm4, flimit4 + + psrad xmm3, 31 + psrad xmm4, 31 + + packssdw xmm3, xmm4 + packsswb xmm3, xmm0 + + movq xmm1, QWORD PTR [esi+eax*8] + + movq xmm2, xmm1 + punpcklbw xmm1, xmm0 + + paddw xmm1, xmm5 + mov ecx, edx + + and ecx, 127 + movdqu xmm4, vp8_rv[ecx*2] + + paddw xmm1, xmm4 + //paddw xmm1, eight8s + psraw xmm1, 4 + + packuswb xmm1, xmm0 + pand xmm1, xmm3 + + pandn xmm3, xmm2 + por xmm1, xmm3 + + and ecx, 15 + movq QWORD PTR d[ecx*8], xmm1 + + mov ecx, edx + sub ecx, 8 + + and ecx, 15 + movq mm0, d[ecx*8] + + movq [esi], mm0 + lea esi, [esi+eax] + + lea edi, [edi+eax] + add edx, 1 + + cmp edx, rows + jl loop_row + + } + + } +} +#if 0 +/**************************************************************************** + * + * ROUTINE : plane_add_noise_wmt + * + * INPUTS : unsigned char *Start starting address of buffer to add gaussian + * noise to + * unsigned int Width width of plane + * unsigned int Height height of plane + * int Pitch distance between subsequent lines of frame + * int q quantizer used to determine amount of noise + * to add + * + * OUTPUTS : None. + * + * RETURNS : void. + * + * FUNCTION : adds gaussian noise to a plane of pixels + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_plane_add_noise_wmt(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a) +{ + unsigned int i; + + __declspec(align(16)) unsigned char blackclamp[16]; + __declspec(align(16)) unsigned char whiteclamp[16]; + __declspec(align(16)) unsigned char bothclamp[16]; + char char_dist[300]; + char Rand[2048]; + double sigma; +// return; + __asm emms + sigma = a + .5 + .6 * (63 - q) / 63.0; + + // set up a lookup table of 256 entries that matches + // a gaussian distribution with sigma determined by q. + // + { + double i; + int next, j; + + next = 0; + + for (i = -32; i < 32; i++) + { + double g = 256 * vp8_gaussian(sigma, 0, 1.0 * i); + int a = (int)(g + .5); + + if (a) + { + for (j = 0; j < a; j++) + { + char_dist[next+j] = (char) i; + } + + next = next + j; + } + + } + + for (next = next; next < 256; next++) + char_dist[next] = 0; + + } + + for (i = 0; i < 2048; i++) + { + Rand[i] = char_dist[rand() & 0xff]; + } + + for (i = 0; i < 16; i++) + { + blackclamp[i] = -char_dist[0]; + whiteclamp[i] = -char_dist[0]; + bothclamp[i] = -2 * char_dist[0]; + } + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = Rand + (rand() & 0xff); + + __asm + { + mov ecx, [Width] + mov esi, Pos + mov edi, Ref + xor eax, eax + + nextset: + movdqu xmm1, [esi+eax] // get the source + + psubusb xmm1, blackclamp // clamp both sides so we don't outrange adding noise + paddusb xmm1, bothclamp + psubusb xmm1, whiteclamp + + movdqu xmm2, [edi+eax] // get the noise for this line + paddb xmm1, xmm2 // add it in + movdqu [esi+eax], xmm1 // store the result + + add eax, 16 // move to the next line + + cmp eax, ecx + jl nextset + + + } + + } +} +#endif +__declspec(align(16)) +static const int four8s[4] = { 8, 8, 8, 8}; +void vp8_mbpost_proc_across_ip_xmm(unsigned char *src, int pitch, int rows, int cols, int flimit) +{ + int r, i; + __declspec(align(16)) + int flimit4[4]; + unsigned char *s = src; + int sumsq; + int sum; + + + flimit = vp8_q2mbl(flimit); + flimit4[0] = + flimit4[1] = + flimit4[2] = + flimit4[3] = flimit; + + for (r = 0; r < rows; r++) + { + + + sumsq = 0; + sum = 0; + + for (i = -8; i <= 6; i++) + { + sumsq += s[i] * s[i]; + sum += s[i]; + } + + __asm + { + mov eax, sumsq + movd xmm7, eax + + mov eax, sum + movd xmm6, eax + + mov esi, s + xor ecx, ecx + + mov edx, cols + add edx, 8 + pxor mm0, mm0 + pxor mm1, mm1 + + pxor xmm0, xmm0 + nextcol4: + + movd xmm1, DWORD PTR [esi+ecx-8] // -8 -7 -6 -5 + movd xmm2, DWORD PTR [esi+ecx+7] // +7 +8 +9 +10 + + punpcklbw xmm1, xmm0 // expanding + punpcklbw xmm2, xmm0 // expanding + + punpcklwd xmm1, xmm0 // expanding to dwords + punpcklwd xmm2, xmm0 // expanding to dwords + + psubd xmm2, xmm1 // 7--8 8--7 9--6 10--5 + paddd xmm1, xmm1 // -8*2 -7*2 -6*2 -5*2 + + paddd xmm1, xmm2 // 7+-8 8+-7 9+-6 10+-5 + pmaddwd xmm1, xmm2 // squared of 7+-8 8+-7 9+-6 10+-5 + + paddd xmm6, xmm2 + paddd xmm7, xmm1 + + pshufd xmm6, xmm6, 0 // duplicate the last ones + pshufd xmm7, xmm7, 0 // duplicate the last ones + + psrldq xmm1, 4 // 8--7 9--6 10--5 0000 + psrldq xmm2, 4 // 8--7 9--6 10--5 0000 + + pshufd xmm3, xmm1, 3 // 0000 8--7 8--7 8--7 squared + pshufd xmm4, xmm2, 3 // 0000 8--7 8--7 8--7 squared + + paddd xmm6, xmm4 + paddd xmm7, xmm3 + + pshufd xmm3, xmm1, 01011111b // 0000 0000 9--6 9--6 squared + pshufd xmm4, xmm2, 01011111b // 0000 0000 9--6 9--6 squared + + paddd xmm7, xmm3 + paddd xmm6, xmm4 + + pshufd xmm3, xmm1, 10111111b // 0000 0000 8--7 8--7 squared + pshufd xmm4, xmm2, 10111111b // 0000 0000 8--7 8--7 squared + + paddd xmm7, xmm3 + paddd xmm6, xmm4 + + movdqa xmm3, xmm6 + pmaddwd xmm3, xmm3 + + movdqa xmm5, xmm7 + pslld xmm5, 4 + + psubd xmm5, xmm7 + psubd xmm5, xmm3 + + psubd xmm5, flimit4 + psrad xmm5, 31 + + packssdw xmm5, xmm0 + packsswb xmm5, xmm0 + + movd xmm1, DWORD PTR [esi+ecx] + movq xmm2, xmm1 + + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + + paddd xmm1, xmm6 + paddd xmm1, four8s + + psrad xmm1, 4 + packssdw xmm1, xmm0 + + packuswb xmm1, xmm0 + pand xmm1, xmm5 + + pandn xmm5, xmm2 + por xmm5, xmm1 + + movd [esi+ecx-8], mm0 + movq mm0, mm1 + + movdq2q mm1, xmm5 + psrldq xmm7, 12 + + psrldq xmm6, 12 + add ecx, 4 + + cmp ecx, edx + jl nextcol4 + + } + s += pitch; + } +} + +#if 0 + +/**************************************************************************** + * + * ROUTINE : plane_add_noise_mmx + * + * INPUTS : unsigned char *Start starting address of buffer to add gaussian + * noise to + * unsigned int Width width of plane + * unsigned int Height height of plane + * int Pitch distance between subsequent lines of frame + * int q quantizer used to determine amount of noise + * to add + * + * OUTPUTS : None. + * + * RETURNS : void. + * + * FUNCTION : adds gaussian noise to a plane of pixels + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void vp8_plane_add_noise_mmx(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a) +{ + unsigned int i; + int Pitch4 = Pitch * 4; + const int noise_amount = 2; + const int noise_adder = 2 * noise_amount + 1; + + __declspec(align(16)) unsigned char blackclamp[16]; + __declspec(align(16)) unsigned char whiteclamp[16]; + __declspec(align(16)) unsigned char bothclamp[16]; + + char char_dist[300]; + char Rand[2048]; + + double sigma; + __asm emms + sigma = a + .5 + .6 * (63 - q) / 63.0; + + // set up a lookup table of 256 entries that matches + // a gaussian distribution with sigma determined by q. + // + { + double i, sum = 0; + int next, j; + + next = 0; + + for (i = -32; i < 32; i++) + { + int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i)); + + if (a) + { + for (j = 0; j < a; j++) + { + char_dist[next+j] = (char) i; + } + + next = next + j; + } + + } + + for (next = next; next < 256; next++) + char_dist[next] = 0; + + } + + for (i = 0; i < 2048; i++) + { + Rand[i] = char_dist[rand() & 0xff]; + } + + for (i = 0; i < 16; i++) + { + blackclamp[i] = -char_dist[0]; + whiteclamp[i] = -char_dist[0]; + bothclamp[i] = -2 * char_dist[0]; + } + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = Rand + (rand() & 0xff); + + __asm + { + mov ecx, [Width] + mov esi, Pos + mov edi, Ref + xor eax, eax + + nextset: + movq mm1, [esi+eax] // get the source + + psubusb mm1, blackclamp // clamp both sides so we don't outrange adding noise + paddusb mm1, bothclamp + psubusb mm1, whiteclamp + + movq mm2, [edi+eax] // get the noise for this line + paddb mm1, mm2 // add it in + movq [esi+eax], mm1 // store the result + + add eax, 8 // move to the next line + + cmp eax, ecx + jl nextset + + + } + + } +} +#else +extern char an[8][64][3072]; +extern int cd[8][64]; + +void vp8_plane_add_noise_mmx(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a) +{ + unsigned int i; + __declspec(align(16)) unsigned char blackclamp[16]; + __declspec(align(16)) unsigned char whiteclamp[16]; + __declspec(align(16)) unsigned char bothclamp[16]; + + + __asm emms + + for (i = 0; i < 16; i++) + { + blackclamp[i] = -cd[a][q]; + whiteclamp[i] = -cd[a][q]; + bothclamp[i] = -2 * cd[a][q]; + } + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = an[a][q] + (rand() & 0xff); + + __asm + { + mov ecx, [Width] + mov esi, Pos + mov edi, Ref + xor eax, eax + + nextset: + movq mm1, [esi+eax] // get the source + + psubusb mm1, blackclamp // clamp both sides so we don't outrange adding noise + paddusb mm1, bothclamp + psubusb mm1, whiteclamp + + movq mm2, [edi+eax] // get the noise for this line + paddb mm1, mm2 // add it in + movq [esi+eax], mm1 // store the result + + add eax, 8 // move to the next line + + cmp eax, ecx + jl nextset + } + } +} + + +void vp8_plane_add_noise_wmt(unsigned char *Start, unsigned int Width, unsigned int Height, int Pitch, int q, int a) +{ + unsigned int i; + + __declspec(align(16)) unsigned char blackclamp[16]; + __declspec(align(16)) unsigned char whiteclamp[16]; + __declspec(align(16)) unsigned char bothclamp[16]; + + __asm emms + + for (i = 0; i < 16; i++) + { + blackclamp[i] = -cd[a][q]; + whiteclamp[i] = -cd[a][q]; + bothclamp[i] = -2 * cd[a][q]; + } + + for (i = 0; i < Height; i++) + { + unsigned char *Pos = Start + i * Pitch; + char *Ref = an[a][q] + (rand() & 0xff); + + __asm + { + mov ecx, [Width] + mov esi, Pos + mov edi, Ref + xor eax, eax + + nextset: + movdqu xmm1, [esi+eax] // get the source + + psubusb xmm1, blackclamp // clamp both sides so we don't outrange adding noise + paddusb xmm1, bothclamp + psubusb xmm1, whiteclamp + + movdqu xmm2, [edi+eax] // get the noise for this line + paddb xmm1, xmm2 // add it in + movdqu [esi+eax], xmm1 // store the result + + add eax, 16 // move to the next line + + cmp eax, ecx + jl nextset + } + } +} + +#endif
diff --git a/vp8/common/x86/postproc_sse2.asm b/vp8/common/x86/postproc_sse2.asm new file mode 100644 index 0000000..bfa36fa --- /dev/null +++ b/vp8/common/x86/postproc_sse2.asm
@@ -0,0 +1,688 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_post_proc_down_and_across_xmm +;( +; unsigned char *src_ptr, +; unsigned char *dst_ptr, +; int src_pixels_per_line, +; int dst_pixels_per_line, +; int rows, +; int cols, +; int flimit +;) +global sym(vp8_post_proc_down_and_across_xmm) +sym(vp8_post_proc_down_and_across_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + ALIGN_STACK 16, rax + ; move the global rd onto the stack, since we don't have enough registers + ; to do PIC addressing + movdqa xmm0, [rd42 GLOBAL] + sub rsp, 16 + movdqa [rsp], xmm0 +%define RD42 [rsp] +%else +%define RD42 [rd42 GLOBAL] +%endif + + + movd xmm2, dword ptr arg(6) ;flimit + punpcklwd xmm2, xmm2 + punpckldq xmm2, xmm2 + punpcklqdq xmm2, xmm2 + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;dst_ptr + + movsxd rcx, DWORD PTR arg(4) ;rows + movsxd rax, DWORD PTR arg(2) ;src_pixels_per_line ; destination pitch? + pxor xmm0, xmm0 ; mm0 = 00000000 + +nextrow: + + xor rdx, rdx ; clear out rdx for use as loop counter +nextcol: + movq xmm3, QWORD PTR [rsi] ; mm4 = r0 p0..p7 + punpcklbw xmm3, xmm0 ; mm3 = p0..p3 + movdqa xmm1, xmm3 ; mm1 = p0..p3 + psllw xmm3, 2 ; + + movq xmm5, QWORD PTR [rsi + rax] ; mm4 = r1 p0..p7 + punpcklbw xmm5, xmm0 ; mm5 = r1 p0..p3 + paddusw xmm3, xmm5 ; mm3 += mm6 + + ; thresholding + movdqa xmm7, xmm1 ; mm7 = r0 p0..p3 + psubusw xmm7, xmm5 ; mm7 = r0 p0..p3 - r1 p0..p3 + psubusw xmm5, xmm1 ; mm5 = r1 p0..p3 - r0 p0..p3 + paddusw xmm7, xmm5 ; mm7 = abs(r0 p0..p3 - r1 p0..p3) + pcmpgtw xmm7, xmm2 + + movq xmm5, QWORD PTR [rsi + 2*rax] ; mm4 = r2 p0..p7 + punpcklbw xmm5, xmm0 ; mm5 = r2 p0..p3 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = r0 p0..p3 + psubusw xmm6, xmm5 ; mm6 = r0 p0..p3 - r2 p0..p3 + psubusw xmm5, xmm1 ; mm5 = r2 p0..p3 - r2 p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(r0 p0..p3 - r2 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + + neg rax + movq xmm5, QWORD PTR [rsi+2*rax] ; mm4 = r-2 p0..p7 + punpcklbw xmm5, xmm0 ; mm5 = r-2 p0..p3 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = r0 p0..p3 + psubusw xmm6, xmm5 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw xmm5, xmm1 ; mm5 = r-2 p0..p3 - p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(r0 p0..p3 - r-2 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + movq xmm4, QWORD PTR [rsi+rax] ; mm4 = r-1 p0..p7 + punpcklbw xmm4, xmm0 ; mm4 = r-1 p0..p3 + paddusw xmm3, xmm4 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = r0 p0..p3 + psubusw xmm6, xmm4 ; mm6 = p0..p3 - r-2 p0..p3 + psubusw xmm4, xmm1 ; mm5 = r-1 p0..p3 - p0..p3 + paddusw xmm6, xmm4 ; mm6 = abs(r0 p0..p3 - r-1 p0..p3) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + + paddusw xmm3, RD42 ; mm3 += round value + psraw xmm3, 3 ; mm3 /= 8 + + pand xmm1, xmm7 ; mm1 select vals > thresh from source + pandn xmm7, xmm3 ; mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; combination + + packuswb xmm1, xmm0 ; pack to bytes + movq QWORD PTR [rdi], xmm1 ; + + neg rax ; pitch is positive + add rsi, 8 + add rdi, 8 + + add rdx, 8 + cmp edx, dword arg(5) ;cols + + jl nextcol + + ; done with the all cols, start the across filtering in place + sub rsi, rdx + sub rdi, rdx + + xor rdx, rdx + movq mm0, QWORD PTR [rdi-8]; + +acrossnextcol: + movq xmm7, QWORD PTR [rdi +rdx -2] + movd xmm4, DWORD PTR [rdi +rdx +6] + + pslldq xmm4, 8 + por xmm4, xmm7 + + movdqa xmm3, xmm4 + psrldq xmm3, 2 + punpcklbw xmm3, xmm0 ; mm3 = p0..p3 + movdqa xmm1, xmm3 ; mm1 = p0..p3 + psllw xmm3, 2 + + + movdqa xmm5, xmm4 + psrldq xmm5, 3 + punpcklbw xmm5, xmm0 ; mm5 = p1..p4 + paddusw xmm3, xmm5 ; mm3 += mm6 + + ; thresholding + movdqa xmm7, xmm1 ; mm7 = p0..p3 + psubusw xmm7, xmm5 ; mm7 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm7, xmm5 ; mm7 = abs(p0..p3 - p1..p4) + pcmpgtw xmm7, xmm2 + + movdqa xmm5, xmm4 + psrldq xmm5, 4 + punpcklbw xmm5, xmm0 ; mm5 = p2..p5 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm5 ; mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + + movdqa xmm5, xmm4 ; mm5 = p-2..p5 + punpcklbw xmm5, xmm0 ; mm5 = p-2..p1 + paddusw xmm3, xmm5 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm5 ; mm6 = p0..p3 - p1..p4 + psubusw xmm5, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm5 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + psrldq xmm4, 1 ; mm4 = p-1..p5 + punpcklbw xmm4, xmm0 ; mm4 = p-1..p2 + paddusw xmm3, xmm4 ; mm3 += mm5 + + ; thresholding + movdqa xmm6, xmm1 ; mm6 = p0..p3 + psubusw xmm6, xmm4 ; mm6 = p0..p3 - p1..p4 + psubusw xmm4, xmm1 ; mm5 = p1..p4 - p0..p3 + paddusw xmm6, xmm4 ; mm6 = abs(p0..p3 - p1..p4) + pcmpgtw xmm6, xmm2 + por xmm7, xmm6 ; accumulate thresholds + + paddusw xmm3, RD42 ; mm3 += round value + psraw xmm3, 3 ; mm3 /= 8 + + pand xmm1, xmm7 ; mm1 select vals > thresh from source + pandn xmm7, xmm3 ; mm7 select vals < thresh from blurred result + paddusw xmm1, xmm7 ; combination + + packuswb xmm1, xmm0 ; pack to bytes + movq QWORD PTR [rdi+rdx-8], mm0 ; store previous four bytes + movdq2q mm0, xmm1 + + add rdx, 8 + cmp edx, dword arg(5) ;cols + jl acrossnextcol; + + ; last 8 pixels + movq QWORD PTR [rdi+rdx-8], mm0 + + ; done with this rwo + add rsi,rax ; next line + mov eax, dword arg(3) ;dst_pixels_per_line ; destination pitch? + add rdi,rax ; next destination + mov eax, dword arg(2) ;src_pixels_per_line ; destination pitch? + + dec rcx ; decrement count + jnz nextrow ; next row + +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + add rsp,16 + pop rsp +%endif + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef RD42 + + +;void vp8_mbpost_proc_down_xmm(unsigned char *dst, +; int pitch, int rows, int cols,int flimit) +extern sym(vp8_rv) +global sym(vp8_mbpost_proc_down_xmm) +sym(vp8_mbpost_proc_down_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 128+16 + + ; unsigned char d[16][8] at [rsp] + ; create flimit2 at [rsp+128] + mov eax, dword ptr arg(4) ;flimit + mov [rsp+128], eax + mov [rsp+128+4], eax + mov [rsp+128+8], eax + mov [rsp+128+12], eax +%define flimit4 [rsp+128] + +%if ABI_IS_32BIT=0 + lea r8, [sym(vp8_rv) GLOBAL] +%endif + + ;rows +=8; + add dword arg(2), 8 + + ;for(c=0; c<cols; c+=8) +loop_col: + mov rsi, arg(0) ; s + pxor xmm0, xmm0 ; + + movsxd rax, dword ptr arg(1) ;pitch ; + neg rax ; rax = -pitch + + lea rsi, [rsi + rax*8]; ; rdi = s[-pitch*8] + neg rax + + + pxor xmm5, xmm5 + pxor xmm6, xmm6 ; + + pxor xmm7, xmm7 ; + mov rdi, rsi + + mov rcx, 15 ; + +loop_initvar: + movq xmm1, QWORD PTR [rdi]; + punpcklbw xmm1, xmm0 ; + + paddw xmm5, xmm1 ; + pmullw xmm1, xmm1 ; + + movdqa xmm2, xmm1 ; + punpcklwd xmm1, xmm0 ; + + punpckhwd xmm2, xmm0 ; + paddd xmm6, xmm1 ; + + paddd xmm7, xmm2 ; + lea rdi, [rdi+rax] ; + + dec rcx + jne loop_initvar + ;save the var and sum + xor rdx, rdx +loop_row: + movq xmm1, QWORD PTR [rsi] ; [s-pitch*8] + movq xmm2, QWORD PTR [rdi] ; [s+pitch*7] + + punpcklbw xmm1, xmm0 + punpcklbw xmm2, xmm0 + + paddw xmm5, xmm2 + psubw xmm5, xmm1 + + pmullw xmm2, xmm2 + movdqa xmm4, xmm2 + + punpcklwd xmm2, xmm0 + punpckhwd xmm4, xmm0 + + paddd xmm6, xmm2 + paddd xmm7, xmm4 + + pmullw xmm1, xmm1 + movdqa xmm2, xmm1 + + punpcklwd xmm1, xmm0 + psubd xmm6, xmm1 + + punpckhwd xmm2, xmm0 + psubd xmm7, xmm2 + + + movdqa xmm3, xmm6 + pslld xmm3, 4 + + psubd xmm3, xmm6 + movdqa xmm1, xmm5 + + movdqa xmm4, xmm5 + pmullw xmm1, xmm1 + + pmulhw xmm4, xmm4 + movdqa xmm2, xmm1 + + punpcklwd xmm1, xmm4 + punpckhwd xmm2, xmm4 + + movdqa xmm4, xmm7 + pslld xmm4, 4 + + psubd xmm4, xmm7 + + psubd xmm3, xmm1 + psubd xmm4, xmm2 + + psubd xmm3, flimit4 + psubd xmm4, flimit4 + + psrad xmm3, 31 + psrad xmm4, 31 + + packssdw xmm3, xmm4 + packsswb xmm3, xmm0 + + movq xmm1, QWORD PTR [rsi+rax*8] + + movq xmm2, xmm1 + punpcklbw xmm1, xmm0 + + paddw xmm1, xmm5 + mov rcx, rdx + + and rcx, 127 +%if ABI_IS_32BIT=1 && CONFIG_PIC=1 + push rax + lea rax, [sym(vp8_rv) GLOBAL] + movdqu xmm4, [rax + rcx*2] ;vp8_rv[rcx*2] + pop rax +%elif ABI_IS_32BIT=0 + movdqu xmm4, [r8 + rcx*2] ;vp8_rv[rcx*2] +%else + movdqu xmm4, [sym(vp8_rv) + rcx*2] +%endif + + paddw xmm1, xmm4 + ;paddw xmm1, eight8s + psraw xmm1, 4 + + packuswb xmm1, xmm0 + pand xmm1, xmm3 + + pandn xmm3, xmm2 + por xmm1, xmm3 + + and rcx, 15 + movq QWORD PTR [rsp + rcx*8], xmm1 ;d[rcx*8] + + mov rcx, rdx + sub rcx, 8 + + and rcx, 15 + movq mm0, [rsp + rcx*8] ;d[rcx*8] + + movq [rsi], mm0 + lea rsi, [rsi+rax] + + lea rdi, [rdi+rax] + add rdx, 1 + + cmp edx, dword arg(2) ;rows + jl loop_row + + add dword arg(0), 8 ; s += 8 + sub dword arg(3), 8 ; cols -= 8 + cmp dword arg(3), 0 + jg loop_col + + add rsp, 128+16 + pop rsp + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef flimit4 + + +;void vp8_mbpost_proc_across_ip_xmm(unsigned char *src, +; int pitch, int rows, int cols,int flimit) +global sym(vp8_mbpost_proc_across_ip_xmm) +sym(vp8_mbpost_proc_across_ip_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 16 + + ; create flimit4 at [rsp] + mov eax, dword ptr arg(4) ;flimit + mov [rsp], eax + mov [rsp+4], eax + mov [rsp+8], eax + mov [rsp+12], eax +%define flimit4 [rsp] + + + ;for(r=0;r<rows;r++) +ip_row_loop: + + xor rdx, rdx ;sumsq=0; + xor rcx, rcx ;sum=0; + mov rsi, arg(0); s + mov rdi, -8 +ip_var_loop: + ;for(i=-8;i<=6;i++) + ;{ + ; sumsq += s[i]*s[i]; + ; sum += s[i]; + ;} + movzx eax, byte [rsi+rdi] + add ecx, eax + mul al + add edx, eax + add rdi, 1 + cmp rdi, 6 + jle ip_var_loop + + + ;mov rax, sumsq + ;movd xmm7, rax + movd xmm7, edx + + ;mov rax, sum + ;movd xmm6, rax + movd xmm6, ecx + + mov rsi, arg(0) ;s + xor rcx, rcx + + movsxd rdx, dword arg(3) ;cols + add rdx, 8 + pxor mm0, mm0 + pxor mm1, mm1 + + pxor xmm0, xmm0 +nextcol4: + + movd xmm1, DWORD PTR [rsi+rcx-8] ; -8 -7 -6 -5 + movd xmm2, DWORD PTR [rsi+rcx+7] ; +7 +8 +9 +10 + + punpcklbw xmm1, xmm0 ; expanding + punpcklbw xmm2, xmm0 ; expanding + + punpcklwd xmm1, xmm0 ; expanding to dwords + punpcklwd xmm2, xmm0 ; expanding to dwords + + psubd xmm2, xmm1 ; 7--8 8--7 9--6 10--5 + paddd xmm1, xmm1 ; -8*2 -7*2 -6*2 -5*2 + + paddd xmm1, xmm2 ; 7+-8 8+-7 9+-6 10+-5 + pmaddwd xmm1, xmm2 ; squared of 7+-8 8+-7 9+-6 10+-5 + + paddd xmm6, xmm2 + paddd xmm7, xmm1 + + pshufd xmm6, xmm6, 0 ; duplicate the last ones + pshufd xmm7, xmm7, 0 ; duplicate the last ones + + psrldq xmm1, 4 ; 8--7 9--6 10--5 0000 + psrldq xmm2, 4 ; 8--7 9--6 10--5 0000 + + pshufd xmm3, xmm1, 3 ; 0000 8--7 8--7 8--7 squared + pshufd xmm4, xmm2, 3 ; 0000 8--7 8--7 8--7 squared + + paddd xmm6, xmm4 + paddd xmm7, xmm3 + + pshufd xmm3, xmm1, 01011111b ; 0000 0000 9--6 9--6 squared + pshufd xmm4, xmm2, 01011111b ; 0000 0000 9--6 9--6 squared + + paddd xmm7, xmm3 + paddd xmm6, xmm4 + + pshufd xmm3, xmm1, 10111111b ; 0000 0000 8--7 8--7 squared + pshufd xmm4, xmm2, 10111111b ; 0000 0000 8--7 8--7 squared + + paddd xmm7, xmm3 + paddd xmm6, xmm4 + + movdqa xmm3, xmm6 + pmaddwd xmm3, xmm3 + + movdqa xmm5, xmm7 + pslld xmm5, 4 + + psubd xmm5, xmm7 + psubd xmm5, xmm3 + + psubd xmm5, flimit4 + psrad xmm5, 31 + + packssdw xmm5, xmm0 + packsswb xmm5, xmm0 + + movd xmm1, DWORD PTR [rsi+rcx] + movq xmm2, xmm1 + + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + + paddd xmm1, xmm6 + paddd xmm1, [four8s GLOBAL] + + psrad xmm1, 4 + packssdw xmm1, xmm0 + + packuswb xmm1, xmm0 + pand xmm1, xmm5 + + pandn xmm5, xmm2 + por xmm5, xmm1 + + movd [rsi+rcx-8], mm0 + movq mm0, mm1 + + movdq2q mm1, xmm5 + psrldq xmm7, 12 + + psrldq xmm6, 12 + add rcx, 4 + + cmp rcx, rdx + jl nextcol4 + + ;s+=pitch; + movsxd rax, dword arg(1) + add arg(0), rax + + sub dword arg(2), 1 ;rows-=1 + cmp dword arg(2), 0 + jg ip_row_loop + + add rsp, 16 + pop rsp + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret +%undef flimit4 + + +;void vp8_plane_add_noise_wmt (unsigned char *Start, unsigned char *noise, +; unsigned char blackclamp[16], +; unsigned char whiteclamp[16], +; unsigned char bothclamp[16], +; unsigned int Width, unsigned int Height, int Pitch) +extern sym(rand) +global sym(vp8_plane_add_noise_wmt) +sym(vp8_plane_add_noise_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +addnoise_loop: + call sym(rand) WRT_PLT + mov rcx, arg(1) ;noise + and rax, 0xff + add rcx, rax + + ; we rely on the fact that the clamping vectors are stored contiguously + ; in black/white/both order. Note that we have to reload this here because + ; rdx could be trashed by rand() + mov rdx, arg(2) ; blackclamp + + + mov rdi, rcx + movsxd rcx, dword arg(5) ;[Width] + mov rsi, arg(0) ;Pos + xor rax,rax + +addnoise_nextset: + movdqu xmm1,[rsi+rax] ; get the source + + psubusb xmm1, [rdx] ;blackclamp ; clamp both sides so we don't outrange adding noise + paddusb xmm1, [rdx+32] ;bothclamp + psubusb xmm1, [rdx+16] ;whiteclamp + + movdqu xmm2,[rdi+rax] ; get the noise for this line + paddb xmm1,xmm2 ; add it in + movdqu [rsi+rax],xmm1 ; store the result + + add rax,16 ; move to the next line + + cmp rax, rcx + jl addnoise_nextset + + movsxd rax, dword arg(7) ; Pitch + add arg(0), rax ; Start += Pitch + sub dword arg(6), 1 ; Height -= 1 + jg addnoise_loop + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +rd42: + times 8 dw 0x04 +four8s: + times 4 dd 8
diff --git a/vp8/common/x86/postproc_x86.h b/vp8/common/x86/postproc_x86.h new file mode 100644 index 0000000..49a1907 --- /dev/null +++ b/vp8/common/x86/postproc_x86.h
@@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef POSTPROC_X86_H +#define POSTPROC_X86_H + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ + +#if HAVE_MMX +extern prototype_postproc_inplace(vp8_mbpost_proc_down_mmx); +extern prototype_postproc(vp8_post_proc_down_and_across_mmx); +extern prototype_postproc_addnoise(vp8_plane_add_noise_mmx); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_postproc_down +#define vp8_postproc_down vp8_mbpost_proc_down_mmx + +#undef vp8_postproc_downacross +#define vp8_postproc_downacross vp8_post_proc_down_and_across_mmx + +#undef vp8_postproc_addnoise +#define vp8_postproc_addnoise vp8_plane_add_noise_mmx + +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_postproc_inplace(vp8_mbpost_proc_down_xmm); +extern prototype_postproc_inplace(vp8_mbpost_proc_across_ip_xmm); +extern prototype_postproc(vp8_post_proc_down_and_across_xmm); +extern prototype_postproc_addnoise(vp8_plane_add_noise_wmt); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_postproc_down +#define vp8_postproc_down vp8_mbpost_proc_down_xmm + +#undef vp8_postproc_across +#define vp8_postproc_across vp8_mbpost_proc_across_ip_xmm + +#undef vp8_postproc_downacross +#define vp8_postproc_downacross vp8_post_proc_down_and_across_xmm + +#undef vp8_postproc_addnoise +#define vp8_postproc_addnoise vp8_plane_add_noise_wmt + + +#endif +#endif + +#endif
diff --git a/vp8/common/x86/recon_mmx.asm b/vp8/common/x86/recon_mmx.asm new file mode 100644 index 0000000..ba60c5d --- /dev/null +++ b/vp8/common/x86/recon_mmx.asm
@@ -0,0 +1,320 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +;void vp8_recon_b_mmx(unsigned char *s, short *q, unsigned char *d, int stride) +global sym(vp8_recon_b_mmx) +sym(vp8_recon_b_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;s + mov rdi, arg(2) ;d + mov rdx, arg(1) ;q + movsxd rax, dword ptr arg(3) ;stride + pxor mm0, mm0 + + movd mm1, [rsi] + punpcklbw mm1, mm0 + paddsw mm1, [rdx] + packuswb mm1, mm0 ; pack and unpack to saturate + movd [rdi], mm1 + + movd mm2, [rsi+16] + punpcklbw mm2, mm0 + paddsw mm2, [rdx+32] + packuswb mm2, mm0 ; pack and unpack to saturate + movd [rdi+rax], mm2 + + movd mm3, [rsi+32] + punpcklbw mm3, mm0 + paddsw mm3, [rdx+64] + packuswb mm3, mm0 ; pack and unpack to saturate + movd [rdi+2*rax], mm3 + + add rdi, rax + movd mm4, [rsi+48] + punpcklbw mm4, mm0 + paddsw mm4, [rdx+96] + packuswb mm4, mm0 ; pack and unpack to saturate + movd [rdi+2*rax], mm4 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem8x8_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem8x8_mmx) +sym(vp8_copy_mem8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movq mm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movq mm1, [rsi+rax] + movq mm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movq [rdi], mm0 + add rsi, rax + + movq [rdi+rcx], mm1 + movq [rdi+rcx*2], mm2 + + + lea rdi, [rdi+rcx*2] + movq mm3, [rsi] + + add rdi, rcx + movq mm4, [rsi+rax] + + movq mm5, [rsi+rax*2] + movq [rdi], mm3 + + lea rsi, [rsi+rax*2] + movq [rdi+rcx], mm4 + + movq [rdi+rcx*2], mm5 + lea rdi, [rdi+rcx*2] + + movq mm0, [rsi+rax] + movq mm1, [rsi+rax*2] + + movq [rdi+rcx], mm0 + movq [rdi+rcx*2],mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem8x4_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem8x4_mmx) +sym(vp8_copy_mem8x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movq mm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movq mm1, [rsi+rax] + movq mm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movq [rdi], mm0 + movq [rdi+rcx], mm1 + + movq [rdi+rcx*2], mm2 + lea rdi, [rdi+rcx*2] + + movq mm3, [rsi+rax] + movq [rdi+rcx], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem16x16_mmx( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem16x16_mmx) +sym(vp8_copy_mem16x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movsxd rax, dword ptr arg(1) ;src_stride; + + mov rdi, arg(2) ;dst; + movsxd rcx, dword ptr arg(3) ;dst_stride + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq mm1, [rsi+rax] + movq mm4, [rsi+rax+8] + + movq mm2, [rsi+rax*2] + movq mm5, [rsi+rax*2+8] + + lea rsi, [rsi+rax*2] + add rsi, rax + + movq [rdi], mm0 + movq [rdi+8], mm3 + + movq [rdi+rcx], mm1 + movq [rdi+rcx+8], mm4 + + movq [rdi+rcx*2], mm2 + movq [rdi+rcx*2+8], mm5 + + lea rdi, [rdi+rcx*2] + add rdi, rcx + + movq mm0, [rsi] + movq mm3, [rsi+8]; + + movq [rdi], mm0 + movq [rdi+8], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/common/x86/recon_sse2.asm b/vp8/common/x86/recon_sse2.asm new file mode 100644 index 0000000..f2685a7 --- /dev/null +++ b/vp8/common/x86/recon_sse2.asm
@@ -0,0 +1,228 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" +;void vp8_recon2b_sse2(unsigned char *s, short *q, unsigned char *d, int stride) +global sym(vp8_recon2b_sse2) +sym(vp8_recon2b_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;s + mov rdi, arg(2) ;d + mov rdx, arg(1) ;q + movsxd rax, dword ptr arg(3) ;stride + pxor xmm0, xmm0 + + movq xmm1, MMWORD PTR [rsi] + punpcklbw xmm1, xmm0 + paddsw xmm1, XMMWORD PTR [rdx] + packuswb xmm1, xmm0 ; pack and unpack to saturate + movq MMWORD PTR [rdi], xmm1 + + + movq xmm2, MMWORD PTR [rsi+8] + punpcklbw xmm2, xmm0 + paddsw xmm2, XMMWORD PTR [rdx+16] + packuswb xmm2, xmm0 ; pack and unpack to saturate + movq MMWORD PTR [rdi+rax], xmm2 + + + movq xmm3, MMWORD PTR [rsi+16] + punpcklbw xmm3, xmm0 + paddsw xmm3, XMMWORD PTR [rdx+32] + packuswb xmm3, xmm0 ; pack and unpack to saturate + movq MMWORD PTR [rdi+rax*2], xmm3 + + add rdi, rax + movq xmm4, MMWORD PTR [rsi+24] + punpcklbw xmm4, xmm0 + paddsw xmm4, XMMWORD PTR [rdx+48] + packuswb xmm4, xmm0 ; pack and unpack to saturate + movq MMWORD PTR [rdi+rax*2], xmm4 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_recon4b_sse2(unsigned char *s, short *q, unsigned char *d, int stride) +global sym(vp8_recon4b_sse2) +sym(vp8_recon4b_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;s + mov rdi, arg(2) ;d + mov rdx, arg(1) ;q + movsxd rax, dword ptr arg(3) ;stride + pxor xmm0, xmm0 + + movdqa xmm1, XMMWORD PTR [rsi] + movdqa xmm5, xmm1 + punpcklbw xmm1, xmm0 + punpckhbw xmm5, xmm0 + paddsw xmm1, XMMWORD PTR [rdx] + paddsw xmm5, XMMWORD PTR [rdx+16] + packuswb xmm1, xmm5 ; pack and unpack to saturate + movdqa XMMWORD PTR [rdi], xmm1 + + + movdqa xmm2, XMMWORD PTR [rsi+16] + movdqa xmm6, xmm2 + punpcklbw xmm2, xmm0 + punpckhbw xmm6, xmm0 + paddsw xmm2, XMMWORD PTR [rdx+32] + paddsw xmm6, XMMWORD PTR [rdx+48] + packuswb xmm2, xmm6 ; pack and unpack to saturate + movdqa XMMWORD PTR [rdi+rax], xmm2 + + + movdqa xmm3, XMMWORD PTR [rsi+32] + movdqa xmm7, xmm3 + punpcklbw xmm3, xmm0 + punpckhbw xmm7, xmm0 + paddsw xmm3, XMMWORD PTR [rdx+64] + paddsw xmm7, XMMWORD PTR [rdx+80] + packuswb xmm3, xmm7 ; pack and unpack to saturate + movdqa XMMWORD PTR [rdi+rax*2], xmm3 + + add rdi, rax + movdqa xmm4, XMMWORD PTR [rsi+48] + movdqa xmm5, xmm4 + punpcklbw xmm4, xmm0 + punpckhbw xmm5, xmm0 + paddsw xmm4, XMMWORD PTR [rdx+96] + paddsw xmm5, XMMWORD PTR [rdx+112] + packuswb xmm4, xmm5 ; pack and unpack to saturate + movdqa XMMWORD PTR [rdi+rax*2], xmm4 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void copy_mem16x16_sse2( +; unsigned char *src, +; int src_stride, +; unsigned char *dst, +; int dst_stride +; ) +global sym(vp8_copy_mem16x16_sse2) +sym(vp8_copy_mem16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src; + movdqu xmm0, [rsi] + + movsxd rax, dword ptr arg(1) ;src_stride; + mov rdi, arg(2) ;dst; + + movdqu xmm1, [rsi+rax] + movdqu xmm2, [rsi+rax*2] + + movsxd rcx, dword ptr arg(3) ;dst_stride + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm0 + add rsi, rax + + movdqa [rdi+rcx], xmm1 + movdqa [rdi+rcx*2],xmm2 + + lea rdi, [rdi+rcx*2] + movdqu xmm3, [rsi] + + add rdi, rcx + movdqu xmm4, [rsi+rax] + + movdqu xmm5, [rsi+rax*2] + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm3 + add rsi, rax + + movdqa [rdi+rcx], xmm4 + movdqa [rdi+rcx*2],xmm5 + + lea rdi, [rdi+rcx*2] + movdqu xmm0, [rsi] + + add rdi, rcx + movdqu xmm1, [rsi+rax] + + movdqu xmm2, [rsi+rax*2] + lea rsi, [rsi+rax*2] + + movdqa [rdi], xmm0 + add rsi, rax + + movdqa [rdi+rcx], xmm1 + + movdqa [rdi+rcx*2], xmm2 + movdqu xmm3, [rsi] + + movdqu xmm4, [rsi+rax] + lea rdi, [rdi+rcx*2] + + add rdi, rcx + movdqu xmm5, [rsi+rax*2] + + lea rsi, [rsi+rax*2] + movdqa [rdi], xmm3 + + add rsi, rax + movdqa [rdi+rcx], xmm4 + + movdqa [rdi+rcx*2],xmm5 + movdqu xmm0, [rsi] + + lea rdi, [rdi+rcx*2] + movdqu xmm1, [rsi+rax] + + add rdi, rcx + movdqu xmm2, [rsi+rax*2] + + lea rsi, [rsi+rax*2] + movdqa [rdi], xmm0 + + movdqa [rdi+rcx], xmm1 + movdqa [rdi+rcx*2],xmm2 + + movdqu xmm3, [rsi+rax] + lea rdi, [rdi+rcx*2] + + movdqa [rdi+rcx], xmm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/common/x86/recon_x86.h b/vp8/common/x86/recon_x86.h new file mode 100644 index 0000000..c469778 --- /dev/null +++ b/vp8/common/x86/recon_x86.h
@@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef RECON_X86_H +#define RECON_X86_H + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ + +#if HAVE_MMX +extern prototype_recon_block(vp8_recon_b_mmx); +extern prototype_copy_block(vp8_copy_mem8x8_mmx); +extern prototype_copy_block(vp8_copy_mem8x4_mmx); +extern prototype_copy_block(vp8_copy_mem16x16_mmx); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_recon_recon +#define vp8_recon_recon vp8_recon_b_mmx + +#undef vp8_recon_copy8x8 +#define vp8_recon_copy8x8 vp8_copy_mem8x8_mmx + +#undef vp8_recon_copy8x4 +#define vp8_recon_copy8x4 vp8_copy_mem8x4_mmx + +#undef vp8_recon_copy16x16 +#define vp8_recon_copy16x16 vp8_copy_mem16x16_mmx + +#endif +#endif + +#if HAVE_SSE2 +extern prototype_recon_block(vp8_recon2b_sse2); +extern prototype_recon_block(vp8_recon4b_sse2); +extern prototype_copy_block(vp8_copy_mem16x16_sse2); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_recon_recon2 +#define vp8_recon_recon2 vp8_recon2b_sse2 + +#undef vp8_recon_recon4 +#define vp8_recon_recon4 vp8_recon4b_sse2 + +#undef vp8_recon_copy16x16 +#define vp8_recon_copy16x16 vp8_copy_mem16x16_sse2 + +#endif +#endif +#endif
diff --git a/vp8/common/x86/subpixel_mmx.asm b/vp8/common/x86/subpixel_mmx.asm new file mode 100644 index 0000000..c502118 --- /dev/null +++ b/vp8/common/x86/subpixel_mmx.asm
@@ -0,0 +1,817 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +%define BLOCK_HEIGHT_WIDTH 4 +%define vp8_filter_weight 128 +%define VP8_FILTER_SHIFT 7 + + +;void vp8_filter_block1d_h6_mmx +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +global sym(vp8_filter_block1d_h6_mmx) +sym(vp8_filter_block1d_h6_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + + movq mm1, [rdx + 16] ; do both the negative taps first!!! + movq mm2, [rdx + 32] ; + movq mm6, [rdx + 48] ; + movq mm7, [rdx + 64] ; + + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(5) ;output_width ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + +nextrow: + movq mm3, [rsi-2] ; mm3 = p-2..p5 + movq mm4, mm3 ; mm4 = p-2..p5 + psrlq mm3, 8 ; mm3 = p-1..p5 + punpcklbw mm3, mm0 ; mm3 = p-1..p2 + pmullw mm3, mm1 ; mm3 *= kernel 1 modifiers. + + movq mm5, mm4 ; mm5 = p-2..p5 + punpckhbw mm4, mm0 ; mm5 = p2..p5 + pmullw mm4, mm7 ; mm5 *= kernel 4 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + movq mm4, mm5 ; mm4 = p-2..p5; + psrlq mm5, 16 ; mm5 = p0..p5; + punpcklbw mm5, mm0 ; mm5 = p0..p3 + pmullw mm5, mm2 ; mm5 *= kernel 2 modifiers + paddsw mm3, mm5 ; mm3 += mm5 + + movq mm5, mm4 ; mm5 = p-2..p5 + psrlq mm4, 24 ; mm4 = p1..p5 + punpcklbw mm4, mm0 ; mm4 = p1..p4 + pmullw mm4, mm6 ; mm5 *= kernel 3 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + ; do outer positive taps + movd mm4, [rsi+3] + punpcklbw mm4, mm0 ; mm5 = p3..p6 + pmullw mm4, [rdx+80] ; mm5 *= kernel 0 modifiers + paddsw mm3, mm4 ; mm3 += mm5 + + punpcklbw mm5, mm0 ; mm5 = p-2..p1 + pmullw mm5, [rdx] ; mm5 *= kernel 5 modifiers + paddsw mm3, mm5 ; mm3 += mm5 + + paddsw mm3, [rd GLOBAL] ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + packuswb mm3, mm0 ; pack and unpack to saturate + punpcklbw mm3, mm0 ; + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, dword ptr arg(2) ;src_pixels_per_line ; next line + add rdi, rax; +%else + movsxd r8, dword ptr arg(2) ;src_pixels_per_line + add rdi, rax; + + add rsi, r8 ; next line +%endif + + dec rcx ; decrement count + jnz nextrow ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +; +; THIS FUNCTION APPEARS TO BE UNUSED +; +;void vp8_filter_block1d_v6_mmx +;( +; short *src_ptr, +; unsigned char *output_ptr, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +global sym(vp8_filter_block1d_v6_mmx) +sym(vp8_filter_block1d_v6_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movq mm5, [rd GLOBAL] + push rbx + mov rbx, arg(6) ;vp8_filter + movq mm1, [rbx + 16] ; do both the negative taps first!!! + movq mm2, [rbx + 32] ; + movq mm6, [rbx + 48] ; + movq mm7, [rbx + 64] ; + + movsxd rdx, dword ptr arg(2) ;pixels_per_line + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + sub rsi, rdx + sub rsi, rdx + movsxd rcx, DWORD PTR arg(4) ;output_height + movsxd rax, DWORD PTR arg(5) ;output_width ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + + +nextrow_v: + movq mm3, [rsi+rdx] ; mm3 = p0..p8 = row -1 + pmullw mm3, mm1 ; mm3 *= kernel 1 modifiers. + + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 2 + pmullw mm4, mm7 ; mm4 *= kernel 4 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 0 + pmullw mm4, mm2 ; mm4 *= kernel 2 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi] ; mm4 = p0..p3 = row -2 + pmullw mm4, [rbx] ; mm4 *= kernel 0 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + add rsi, rdx ; move source forward 1 line to avoid 3 * pitch + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 1 + pmullw mm4, mm6 ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 3 + pmullw mm4, [rbx +80] ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + paddsw mm3, mm5 ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + packuswb mm3, mm0 ; pack and saturate + + movd [rdi],mm3 ; store the results in the destination + + add rdi,rax; + + dec rcx ; decrement count + jnz nextrow_v ; next row + + pop rbx + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1dc_v6_mmx +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int output_pitch, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +global sym(vp8_filter_block1dc_v6_mmx) +sym(vp8_filter_block1dc_v6_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movq mm5, [rd GLOBAL] + push rbx + mov rbx, arg(7) ;vp8_filter + movq mm1, [rbx + 16] ; do both the negative taps first!!! + movq mm2, [rbx + 32] ; + movq mm6, [rbx + 48] ; + movq mm7, [rbx + 64] ; + + movsxd rdx, dword ptr arg(3) ;pixels_per_line + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + sub rsi, rdx + sub rsi, rdx + movsxd rcx, DWORD PTR arg(5) ;output_height + movsxd rax, DWORD PTR arg(2) ;output_pitch ; destination pitch? + pxor mm0, mm0 ; mm0 = 00000000 + + +nextrow_cv: + movq mm3, [rsi+rdx] ; mm3 = p0..p8 = row -1 + pmullw mm3, mm1 ; mm3 *= kernel 1 modifiers. + + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 2 + pmullw mm4, mm7 ; mm4 *= kernel 4 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 0 + pmullw mm4, mm2 ; mm4 *= kernel 2 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi] ; mm4 = p0..p3 = row -2 + pmullw mm4, [rbx] ; mm4 *= kernel 0 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + add rsi, rdx ; move source forward 1 line to avoid 3 * pitch + movq mm4, [rsi + 2*rdx] ; mm4 = p0..p3 = row 1 + pmullw mm4, mm6 ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + movq mm4, [rsi + 4*rdx] ; mm4 = p0..p3 = row 3 + pmullw mm4, [rbx +80] ; mm4 *= kernel 3 modifiers. + paddsw mm3, mm4 ; mm3 += mm4 + + + paddsw mm3, mm5 ; mm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; mm3 /= 128 + packuswb mm3, mm0 ; pack and saturate + + movd [rdi],mm3 ; store the results in the destination + ; the subsequent iterations repeat 3 out of 4 of these reads. Since the + ; recon block should be in cache this shouldn't cost much. Its obviously + ; avoidable!!!. + lea rdi, [rdi+rax] ; + dec rcx ; decrement count + jnz nextrow_cv ; next row + + pop rbx + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict8x8_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x8_mmx) +sym(vp8_bilinear_predict8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = bilinear_filters_mmx[xoffset]; + ;const short *VFilter = bilinear_filters_mmx[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + shl rax, 5 ; offset * 32 + lea rcx, [sym(vp8_bilinear_filters_mmx) GLOBAL] + + add rax, rcx ; HFilter + mov rsi, arg(0) ;src_ptr ; + + movsxd rdx, dword ptr arg(5) ;dst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + + shl rax, 5 ; offset*32 + add rax, rcx ; VFilter + + lea rcx, [rdi+rdx*8] ; + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + + + ; get the first horizontal line done ; + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + add rsi, rdx ; next line +next_row_8x8: + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + movq mm5, mm7 ; + movq mm6, mm7 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 + + pmullw mm5, [rax] ; + pmullw mm6, [rax] ; + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + + pmullw mm3, [rax+16] ; + pmullw mm4, [rax+16] ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + packuswb mm3, mm4 + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch + add rsi, rdx ; next line + add rdi, r8 ;dst_pitch +%endif + cmp rdi, rcx ; + jne next_row_8x8 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict8x4_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict8x4_mmx) +sym(vp8_bilinear_predict8x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = bilinear_filters_mmx[xoffset]; + ;const short *VFilter = bilinear_filters_mmx[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + lea rcx, [sym(vp8_bilinear_filters_mmx) GLOBAL] + shl rax, 5 + + mov rsi, arg(0) ;src_ptr ; + add rax, rcx + + movsxd rdx, dword ptr arg(5) ;dst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + shl rax, 5 + + add rax, rcx + lea rcx, [rdi+rdx*4] ; + + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + ; get the first horizontal line done ; + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + add rsi, rdx ; next line +next_row_8x4: + movq mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movq mm4, mm3 ; make a copy of current line + + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + punpckhbw mm4, mm0 ; + + pmullw mm3, mm1 ; + pmullw mm4, mm1 ; + + movq mm5, [rsi+1] ; + movq mm6, mm5 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 ; + + pmullw mm5, mm2 ; + pmullw mm6, mm2 ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + movq mm5, mm7 ; + movq mm6, mm7 ; + + punpcklbw mm5, mm0 ; + punpckhbw mm6, mm0 + + pmullw mm5, [rax] ; + pmullw mm6, [rax] ; + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + movq mm7, mm3 ; + packuswb mm7, mm4 ; + + + pmullw mm3, [rax+16] ; + pmullw mm4, [rax+16] ; + + paddw mm3, mm5 ; + paddw mm4, mm6 ; + + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw mm4, [rd GLOBAL] ; + psraw mm4, VP8_FILTER_SHIFT ; + + packuswb mm3, mm4 + + movq [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch + add rsi, rdx ; next line + add rdi, r8 +%endif + cmp rdi, rcx ; + jne next_row_8x4 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void bilinear_predict4x4_mmx +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +global sym(vp8_bilinear_predict4x4_mmx) +sym(vp8_bilinear_predict4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = bilinear_filters_mmx[xoffset]; + ;const short *VFilter = bilinear_filters_mmx[yoffset]; + + movsxd rax, dword ptr arg(2) ;xoffset + mov rdi, arg(4) ;dst_ptr ; + + lea rcx, [sym(vp8_bilinear_filters_mmx) GLOBAL] + shl rax, 5 + + add rax, rcx ; HFilter + mov rsi, arg(0) ;src_ptr ; + + movsxd rdx, dword ptr arg(5) ;ldst_pitch + movq mm1, [rax] ; + + movq mm2, [rax+16] ; + movsxd rax, dword ptr arg(3) ;yoffset + + pxor mm0, mm0 ; + shl rax, 5 + + add rax, rcx + lea rcx, [rdi+rdx*4] ; + + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line ; + + ; get the first horizontal line done ; + movd mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + + pmullw mm3, mm1 ; + movd mm5, [rsi+1] ; + + punpcklbw mm5, mm0 ; + pmullw mm5, mm2 ; + + paddw mm3, mm5 ; + paddw mm3, [rd GLOBAL] ; xmm3 += round value + + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movq mm7, mm3 ; + packuswb mm7, mm0 ; + + add rsi, rdx ; next line +next_row_4x4: + movd mm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + punpcklbw mm3, mm0 ; xx 00 01 02 03 04 05 06 + + pmullw mm3, mm1 ; + movd mm5, [rsi+1] ; + + punpcklbw mm5, mm0 ; + pmullw mm5, mm2 ; + + paddw mm3, mm5 ; + + movq mm5, mm7 ; + punpcklbw mm5, mm0 ; + + pmullw mm5, [rax] ; + paddw mm3, [rd GLOBAL] ; xmm3 += round value + + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + movq mm7, mm3 ; + + packuswb mm7, mm0 ; + + pmullw mm3, [rax+16] ; + paddw mm3, mm5 ; + + + paddw mm3, [rd GLOBAL] ; xmm3 += round value + psraw mm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + packuswb mm3, mm0 + movd [rdi], mm3 ; store the results in the destination + +%if ABI_IS_32BIT + add rsi, rdx ; next line + add rdi, dword ptr arg(5) ;dst_pitch ; +%else + movsxd r8, dword ptr arg(5) ;dst_pitch ; + add rsi, rdx ; next line + add rdi, r8 +%endif + + cmp rdi, rcx ; + jne next_row_4x4 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +SECTION_RODATA +align 16 +rd: + times 4 dw 0x40 + +align 16 +global sym(vp8_six_tap_mmx) +sym(vp8_six_tap_mmx): + times 8 dw 0 + times 8 dw 0 + times 8 dw 128 + times 8 dw 0 + times 8 dw 0 + times 8 dw 0 + + times 8 dw 0 + times 8 dw -6 + times 8 dw 123 + times 8 dw 12 + times 8 dw -1 + times 8 dw 0 + + times 8 dw 2 + times 8 dw -11 + times 8 dw 108 + times 8 dw 36 + times 8 dw -8 + times 8 dw 1 + + times 8 dw 0 + times 8 dw -9 + times 8 dw 93 + times 8 dw 50 + times 8 dw -6 + times 8 dw 0 + + times 8 dw 3 + times 8 dw -16 + times 8 dw 77 + times 8 dw 77 + times 8 dw -16 + times 8 dw 3 + + times 8 dw 0 + times 8 dw -6 + times 8 dw 50 + times 8 dw 93 + times 8 dw -9 + times 8 dw 0 + + times 8 dw 1 + times 8 dw -8 + times 8 dw 36 + times 8 dw 108 + times 8 dw -11 + times 8 dw 2 + + times 8 dw 0 + times 8 dw -1 + times 8 dw 12 + times 8 dw 123 + times 8 dw -6 + times 8 dw 0 + + +align 16 +global sym(vp8_bilinear_filters_mmx) +sym(vp8_bilinear_filters_mmx): + times 8 dw 128 + times 8 dw 0 + + times 8 dw 112 + times 8 dw 16 + + times 8 dw 96 + times 8 dw 32 + + times 8 dw 80 + times 8 dw 48 + + times 8 dw 64 + times 8 dw 64 + + times 8 dw 48 + times 8 dw 80 + + times 8 dw 32 + times 8 dw 96 + + times 8 dw 16 + times 8 dw 112
diff --git a/vp8/common/x86/subpixel_sse2.asm b/vp8/common/x86/subpixel_sse2.asm new file mode 100644 index 0000000..dee04f2 --- /dev/null +++ b/vp8/common/x86/subpixel_sse2.asm
@@ -0,0 +1,1032 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define BLOCK_HEIGHT_WIDTH 4 +%define VP8_FILTER_WEIGHT 128 +%define VP8_FILTER_SHIFT 7 + + +;/************************************************************************************ +; Notes: filter_block1d_h6 applies a 6 tap filter horizontally to the input pixels. The +; input pixel array has output_height rows. This routine assumes that output_height is an +; even number. This function handles 8 pixels in horizontal direction, calculating ONE +; rows each iteration to take advantage of the 128 bits operations. +;*************************************************************************************/ +;void vp8_filter_block1d8_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short *vp8_filter +;) +global sym(vp8_filter_block1d8_h6_sse2) +sym(vp8_filter_block1d8_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;output_width +%endif + pxor xmm0, xmm0 ; clear xmm0 for unpack + +filter_block1d8_h6_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [rd GLOBAL] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm4 + lea rsi, [rsi + rax] + +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(5) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx + + jnz filter_block1d8_h6_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d16_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short *vp8_filter +;) +;/************************************************************************************ +; Notes: filter_block1d_h6 applies a 6 tap filter horizontally to the input pixels. The +; input pixel array has output_height rows. This routine assumes that output_height is an +; even number. This function handles 8 pixels in horizontal direction, calculating ONE +; rows each iteration to take advantage of the 128 bits operations. +;*************************************************************************************/ +global sym(vp8_filter_block1d16_h6_sse2) +sym(vp8_filter_block1d16_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rdx, arg(6) ;vp8_filter + mov rsi, arg(0) ;src_ptr + + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(4) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;output_width +%endif + + pxor xmm0, xmm0 ; clear xmm0 for unpack + +filter_block1d16_h6_sse2_rowloop: + movq xmm3, MMWORD PTR [rsi - 2] + movq xmm1, MMWORD PTR [rsi + 6] + + movq xmm2, MMWORD PTR [rsi +14] + pslldq xmm2, 8 + + por xmm2, xmm1 + prefetcht2 [rsi+rax-2] + + pslldq xmm1, 8 + por xmm1, xmm3 + + movdqa xmm4, xmm1 + movdqa xmm5, xmm1 + + movdqa xmm6, xmm1 + movdqa xmm7, xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm1, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm1, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm1, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm1 + paddsw xmm4, [rd GLOBAL] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm4 + + movdqa xmm3, xmm2 + movdqa xmm4, xmm2 + + movdqa xmm5, xmm2 + movdqa xmm6, xmm2 + + movdqa xmm7, xmm2 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + psrldq xmm4, 1 ; xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 + + pmullw xmm3, XMMWORD PTR [rdx] ; x[-2] * H[-2]; Tap 1 + punpcklbw xmm4, xmm0 ; xx06 xx05 xx04 xx03 xx02 xx01 xx00 xx-1 + + psrldq xmm5, 2 ; xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 + pmullw xmm4, XMMWORD PTR [rdx+16] ; x[-1] * H[-1]; Tap 2 + + + punpcklbw xmm5, xmm0 ; xx07 xx06 xx05 xx04 xx03 xx02 xx01 xx00 + psrldq xmm6, 3 ; xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 + + pmullw xmm5, [rdx+32] ; x[ 0] * H[ 0]; Tap 3 + + punpcklbw xmm6, xmm0 ; xx08 xx07 xx06 xx05 xx04 xx03 xx02 xx01 + psrldq xmm7, 4 ; xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 02 + + pmullw xmm6, [rdx+48] ; x[ 1] * h[ 1] ; Tap 4 + + punpcklbw xmm7, xmm0 ; xx09 xx08 xx07 xx06 xx05 xx04 xx03 xx02 + psrldq xmm2, 5 ; xx xx xx xx xx 0d 0c 0b 0a 09 08 07 06 05 04 03 + + pmullw xmm7, [rdx+64] ; x[ 2] * h[ 2] ; Tap 5 + + punpcklbw xmm2, xmm0 ; xx0a xx09 xx08 xx07 xx06 xx05 xx04 xx03 + pmullw xmm2, [rdx+80] ; x[ 3] * h[ 3] ; Tap 6 + + + paddsw xmm4, xmm7 + paddsw xmm4, xmm5 + + paddsw xmm4, xmm3 + paddsw xmm4, xmm6 + + paddsw xmm4, xmm2 + paddsw xmm4, [rd GLOBAL] + + psraw xmm4, 7 + + packuswb xmm4, xmm0 + punpcklbw xmm4, xmm0 + + movdqa XMMWORD Ptr [rdi+16], xmm4 + + lea rsi, [rsi + rax] +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(5) ;[output_width] +%else + add rdi, r8 +%endif + + dec rcx + jnz filter_block1d16_h6_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_filter_block1d8_v6_sse2 +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int pixels_per_line, +; unsigned int pixel_step, +; unsigned int output_height, +; unsigned int output_width, +; short * vp8_filter +;) +;/************************************************************************************ +; Notes: filter_block1d8_v6 applies a 6 tap filter vertically to the input pixels. The +; input pixel array has output_height rows. +;*************************************************************************************/ +global sym(vp8_filter_block1d8_v6_sse2) +sym(vp8_filter_block1d8_v6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(7) ;vp8_filter + movsxd rdx, dword ptr arg(3) ;pixels_per_line + + mov rdi, arg(1) ;output_ptr + mov rsi, arg(0) ;src_ptr + + sub rsi, rdx + sub rsi, rdx + + movsxd rcx, DWORD PTR arg(5) ;[output_height] + pxor xmm0, xmm0 ; clear xmm0 + + movdqa xmm7, XMMWORD PTR [rd GLOBAL] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(2) ; dst_ptich +%endif + +vp8_filter_block1d8_v6_sse2_loop: + movdqa xmm1, XMMWORD PTR [rsi] + pmullw xmm1, [rax] + + movdqa xmm2, XMMWORD PTR [rsi + rdx] + pmullw xmm2, [rax + 16] + + movdqa xmm3, XMMWORD PTR [rsi + rdx * 2] + pmullw xmm3, [rax + 32] + + movdqa xmm5, XMMWORD PTR [rsi + rdx * 4] + pmullw xmm5, [rax + 64] + + add rsi, rdx + movdqa xmm4, XMMWORD PTR [rsi + rdx * 2] + + pmullw xmm4, [rax + 48] + movdqa xmm6, XMMWORD PTR [rsi + rdx * 4] + + pmullw xmm6, [rax + 80] + + paddsw xmm2, xmm5 + paddsw xmm2, xmm3 + + paddsw xmm2, xmm1 + paddsw xmm2, xmm4 + + paddsw xmm2, xmm6 + paddsw xmm2, xmm7 + + psraw xmm2, 7 + packuswb xmm2, xmm0 ; pack and saturate + + movq QWORD PTR [rdi], xmm2 ; store the results in the destination +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(2) ;[dst_ptich] +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz vp8_filter_block1d8_v6_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_unpack_block1d16_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int output_height, +; unsigned int output_width +;) +global sym(vp8_unpack_block1d16_h6_sse2) +sym(vp8_unpack_block1d16_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(3) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source + + pxor xmm0, xmm0 ; clear xmm0 for unpack +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(4) ;output_width ; Pitch for Source +%endif + +unpack_block1d16_h6_sse2_rowloop: + movq xmm1, MMWORD PTR [rsi] ; 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 -2 + movq xmm3, MMWORD PTR [rsi+8] ; make copy of xmm1 + + punpcklbw xmm3, xmm0 ; xx05 xx04 xx03 xx02 xx01 xx01 xx-1 xx-2 + punpcklbw xmm1, xmm0 + + movdqa XMMWORD Ptr [rdi], xmm1 + movdqa XMMWORD Ptr [rdi + 16], xmm3 + + lea rsi, [rsi + rax] +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(4) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx + jnz unpack_block1d16_h6_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_unpack_block1d8_h6_sse2 +;( +; unsigned char *src_ptr, +; unsigned short *output_ptr, +; unsigned int src_pixels_per_line, +; unsigned int output_height, +; unsigned int output_width +;) +global sym(vp8_unpack_block1d8_h6_sse2) +sym(vp8_unpack_block1d8_h6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(1) ;output_ptr + + movsxd rcx, dword ptr arg(3) ;output_height + movsxd rax, dword ptr arg(2) ;src_pixels_per_line ; Pitch for Source + + pxor xmm0, xmm0 ; clear xmm0 for unpack +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(4) ;output_width ; Pitch for Source +%endif + +unpack_block1d8_h6_sse2_rowloop: + movq xmm1, MMWORD PTR [rsi] ; 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 -1 -2 + lea rsi, [rsi + rax] + + punpcklbw xmm1, xmm0 + movdqa XMMWORD Ptr [rdi], xmm1 + +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(4) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx + jnz unpack_block1d8_h6_sse2_rowloop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_pack_block1d8_v6_sse2 +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int pixels_per_line, +; unsigned int output_height, +; unsigned int output_width +;) +global sym(vp8_pack_block1d8_v6_sse2) +sym(vp8_pack_block1d8_v6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, dword ptr arg(3) ;pixels_per_line + mov rdi, arg(1) ;output_ptr + + mov rsi, arg(0) ;src_ptr + movsxd rcx, DWORD PTR arg(4) ;[output_height] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;output_width ; Pitch for Source +%endif + +pack_block1d8_v6_sse2_loop: + movdqa xmm0, XMMWORD PTR [rsi] + packuswb xmm0, xmm0 + + movq QWORD PTR [rdi], xmm0 ; store the results in the destination + lea rsi, [rsi+rdx] + +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(5) ;[output_width] +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz pack_block1d8_v6_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_pack_block1d16_v6_sse2 +;( +; short *src_ptr, +; unsigned char *output_ptr, +; int dst_ptich, +; unsigned int pixels_per_line, +; unsigned int output_height, +; unsigned int output_width +;) +global sym(vp8_pack_block1d16_v6_sse2) +sym(vp8_pack_block1d16_v6_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + movsxd rdx, dword ptr arg(3) ;pixels_per_line + mov rdi, arg(1) ;output_ptr + + mov rsi, arg(0) ;src_ptr + movsxd rcx, DWORD PTR arg(4) ;[output_height] +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(2) ;dst_pitch +%endif + +pack_block1d16_v6_sse2_loop: + movdqa xmm0, XMMWORD PTR [rsi] + movdqa xmm1, XMMWORD PTR [rsi+16] + + packuswb xmm0, xmm1 + movdqa XMMWORD PTR [rdi], xmm0 ; store the results in the destination + + add rsi, rdx +%if ABI_IS_32BIT + add rdi, DWORD Ptr arg(2) ;dst_pitch +%else + add rdi, r8 +%endif + dec rcx ; decrement count + jnz pack_block1d16_v6_sse2_loop ; next row + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_bilinear_predict16x16_sse2 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +extern sym(vp8_bilinear_filters_mmx) +global sym(vp8_bilinear_predict16x16_sse2) +sym(vp8_bilinear_predict16x16_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ;const short *HFilter = bilinear_filters_mmx[xoffset] + ;const short *VFilter = bilinear_filters_mmx[yoffset] + + lea rcx, [sym(vp8_bilinear_filters_mmx) GLOBAL] + movsxd rax, dword ptr arg(2) ;xoffset + + cmp rax, 0 ;skip first_pass filter if xoffset=0 + je b16x16_sp_only + + shl rax, 5 + add rax, rcx ;HFilter + + mov rdi, arg(4) ;dst_ptr + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + movsxd rax, dword ptr arg(3) ;yoffset + + cmp rax, 0 ;skip second_pass filter if yoffset=0 + je b16x16_fp_only + + shl rax, 5 + add rax, rcx ;VFilter + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + pxor xmm0, xmm0 + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(5) ;dst_pitch +%endif + ; get the first horizontal line done + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [rd GLOBAL] + psraw xmm4, VP8_FILTER_SHIFT + + movdqa xmm7, xmm3 + packuswb xmm7, xmm4 + + add rsi, rdx ; next line +next_row: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + movdqa xmm5, xmm7 + movdqa xmm6, xmm7 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, [rax] + pmullw xmm6, [rax] + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [rd GLOBAL] + psraw xmm4, VP8_FILTER_SHIFT + + movdqa xmm7, xmm3 + packuswb xmm7, xmm4 + + pmullw xmm3, [rax+16] + pmullw xmm4, [rax+16] + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [rd GLOBAL] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rdx ; next line +%if ABI_IS_32BIT + add rdi, DWORD PTR arg(5) ;dst_pitch +%else + add rdi, r8 +%endif + + cmp rdi, rcx + jne next_row + + jmp done + +b16x16_sp_only: + movsxd rax, dword ptr arg(3) ;yoffset + shl rax, 5 + add rax, rcx ;VFilter + + mov rdi, arg(4) ;dst_ptr + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + + pxor xmm0, xmm0 + + ; get the first horizontal line done + movdqu xmm7, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + + add rsi, rax ; next line +next_row_spo: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + + movdqa xmm5, xmm7 + movdqa xmm6, xmm7 + + movdqa xmm4, xmm3 ; make a copy of current line + movdqa xmm7, xmm3 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm5, xmm1 + pmullw xmm6, xmm1 + pmullw xmm3, xmm2 + pmullw xmm4, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [rd GLOBAL] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rax ; next line + add rdi, rdx ;dst_pitch + cmp rdi, rcx + jne next_row_spo + + jmp done + +b16x16_fp_only: + lea rcx, [rdi+rdx*8] + lea rcx, [rcx+rdx*8] + movsxd rax, dword ptr arg(1) ;src_pixels_per_line + pxor xmm0, xmm0 + +next_row_fpo: + movdqu xmm3, [rsi] ; xx 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + movdqa xmm4, xmm3 ; make a copy of current line + + punpcklbw xmm3, xmm0 ; xx 00 01 02 03 04 05 06 + punpckhbw xmm4, xmm0 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm1 + + movdqu xmm5, [rsi+1] + movdqa xmm6, xmm5 + + punpcklbw xmm5, xmm0 + punpckhbw xmm6, xmm0 + + pmullw xmm5, xmm2 + pmullw xmm6, xmm2 + + paddw xmm3, xmm5 + paddw xmm4, xmm6 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + paddw xmm4, [rd GLOBAL] + psraw xmm4, VP8_FILTER_SHIFT + + packuswb xmm3, xmm4 + movdqa [rdi], xmm3 ; store the results in the destination + + add rsi, rax ; next line + add rdi, rdx ; dst_pitch + cmp rdi, rcx + jne next_row_fpo + +done: + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_bilinear_predict8x8_sse2 +;( +; unsigned char *src_ptr, +; int src_pixels_per_line, +; int xoffset, +; int yoffset, +; unsigned char *dst_ptr, +; int dst_pitch +;) +extern sym(vp8_bilinear_filters_mmx) +global sym(vp8_bilinear_predict8x8_sse2) +sym(vp8_bilinear_predict8x8_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + ALIGN_STACK 16, rax + sub rsp, 144 ; reserve 144 bytes + + ;const short *HFilter = bilinear_filters_mmx[xoffset] + ;const short *VFilter = bilinear_filters_mmx[yoffset] + lea rcx, [sym(vp8_bilinear_filters_mmx) GLOBAL] + + mov rsi, arg(0) ;src_ptr + movsxd rdx, dword ptr arg(1) ;src_pixels_per_line + + ;Read 9-line unaligned data in and put them on stack. This gives a big + ;performance boost. + movdqu xmm0, [rsi] + lea rax, [rdx + rdx*2] + movdqu xmm1, [rsi+rdx] + movdqu xmm2, [rsi+rdx*2] + add rsi, rax + movdqu xmm3, [rsi] + movdqu xmm4, [rsi+rdx] + movdqu xmm5, [rsi+rdx*2] + add rsi, rax + movdqu xmm6, [rsi] + movdqu xmm7, [rsi+rdx] + + movdqa XMMWORD PTR [rsp], xmm0 + + movdqu xmm0, [rsi+rdx*2] + + movdqa XMMWORD PTR [rsp+16], xmm1 + movdqa XMMWORD PTR [rsp+32], xmm2 + movdqa XMMWORD PTR [rsp+48], xmm3 + movdqa XMMWORD PTR [rsp+64], xmm4 + movdqa XMMWORD PTR [rsp+80], xmm5 + movdqa XMMWORD PTR [rsp+96], xmm6 + movdqa XMMWORD PTR [rsp+112], xmm7 + movdqa XMMWORD PTR [rsp+128], xmm0 + + movsxd rax, dword ptr arg(2) ;xoffset + shl rax, 5 + add rax, rcx ;HFilter + + mov rdi, arg(4) ;dst_ptr + movsxd rdx, dword ptr arg(5) ;dst_pitch + + movdqa xmm1, [rax] + movdqa xmm2, [rax+16] + + movsxd rax, dword ptr arg(3) ;yoffset + shl rax, 5 + add rax, rcx ;VFilter + + lea rcx, [rdi+rdx*8] + + movdqa xmm5, [rax] + movdqa xmm6, [rax+16] + + pxor xmm0, xmm0 + + ; get the first horizontal line done + movdqa xmm3, XMMWORD PTR [rsp] + movdqa xmm4, xmm3 ; make a copy of current line + psrldq xmm4, 1 + + punpcklbw xmm3, xmm0 ; 00 01 02 03 04 05 06 07 + punpcklbw xmm4, xmm0 ; 01 02 03 04 05 06 07 08 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm2 + + paddw xmm3, xmm4 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movdqa xmm7, xmm3 + add rsp, 16 ; next line +next_row8x8: + movdqa xmm3, XMMWORD PTR [rsp] ; 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 + movdqa xmm4, xmm3 ; make a copy of current line + psrldq xmm4, 1 + + punpcklbw xmm3, xmm0 ; 00 01 02 03 04 05 06 07 + punpcklbw xmm4, xmm0 ; 01 02 03 04 05 06 07 08 + + pmullw xmm3, xmm1 + pmullw xmm4, xmm2 + + paddw xmm3, xmm4 + pmullw xmm7, xmm5 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + movdqa xmm4, xmm3 + + pmullw xmm3, xmm6 + paddw xmm3, xmm7 + + movdqa xmm7, xmm4 + + paddw xmm3, [rd GLOBAL] ; xmm3 += round value + psraw xmm3, VP8_FILTER_SHIFT ; xmm3 /= 128 + + packuswb xmm3, xmm0 + movq [rdi], xmm3 ; store the results in the destination + + add rsp, 16 ; next line + add rdi, rdx + + cmp rdi, rcx + jne next_row8x8 + + ;add rsp, 144 + pop rsp + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +rd: + times 8 dw 0x40
diff --git a/vp8/common/x86/subpixel_x86.h b/vp8/common/x86/subpixel_x86.h new file mode 100644 index 0000000..efa7b2e --- /dev/null +++ b/vp8/common/x86/subpixel_x86.h
@@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef SUBPIXEL_X86_H +#define SUBPIXEL_X86_H + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ + +#if HAVE_MMX +extern prototype_subpixel_predict(vp8_sixtap_predict16x16_mmx); +extern prototype_subpixel_predict(vp8_sixtap_predict8x8_mmx); +extern prototype_subpixel_predict(vp8_sixtap_predict8x4_mmx); +extern prototype_subpixel_predict(vp8_sixtap_predict4x4_mmx); +extern prototype_subpixel_predict(vp8_bilinear_predict16x16_mmx); +extern prototype_subpixel_predict(vp8_bilinear_predict8x8_mmx); +extern prototype_subpixel_predict(vp8_bilinear_predict8x4_mmx); +extern prototype_subpixel_predict(vp8_bilinear_predict4x4_mmx); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_subpix_sixtap16x16 +#define vp8_subpix_sixtap16x16 vp8_sixtap_predict16x16_mmx + +#undef vp8_subpix_sixtap8x8 +#define vp8_subpix_sixtap8x8 vp8_sixtap_predict8x8_mmx + +#undef vp8_subpix_sixtap8x4 +#define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_mmx + +#undef vp8_subpix_sixtap4x4 +#define vp8_subpix_sixtap4x4 vp8_sixtap_predict4x4_mmx + +#undef vp8_subpix_bilinear16x16 +#define vp8_subpix_bilinear16x16 vp8_bilinear_predict16x16_mmx + +#undef vp8_subpix_bilinear8x8 +#define vp8_subpix_bilinear8x8 vp8_bilinear_predict8x8_mmx + +#undef vp8_subpix_bilinear8x4 +#define vp8_subpix_bilinear8x4 vp8_bilinear_predict8x4_mmx + +#undef vp8_subpix_bilinear4x4 +#define vp8_subpix_bilinear4x4 vp8_bilinear_predict4x4_mmx + +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_subpixel_predict(vp8_sixtap_predict16x16_sse2); +extern prototype_subpixel_predict(vp8_sixtap_predict8x8_sse2); +extern prototype_subpixel_predict(vp8_sixtap_predict8x4_sse2); +extern prototype_subpixel_predict(vp8_bilinear_predict16x16_sse2); +extern prototype_subpixel_predict(vp8_bilinear_predict8x8_sse2); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_subpix_sixtap16x16 +#define vp8_subpix_sixtap16x16 vp8_sixtap_predict16x16_sse2 + +#undef vp8_subpix_sixtap8x8 +#define vp8_subpix_sixtap8x8 vp8_sixtap_predict8x8_sse2 + +#undef vp8_subpix_sixtap8x4 +#define vp8_subpix_sixtap8x4 vp8_sixtap_predict8x4_sse2 + +#undef vp8_subpix_bilinear16x16 +#define vp8_subpix_bilinear16x16 vp8_bilinear_predict16x16_sse2 + +#undef vp8_subpix_bilinear8x8 +#define vp8_subpix_bilinear8x8 vp8_bilinear_predict8x8_sse2 + +#endif +#endif + +#endif
diff --git a/vp8/common/x86/vp8_asm_stubs.c b/vp8/common/x86/vp8_asm_stubs.c new file mode 100644 index 0000000..68454f7 --- /dev/null +++ b/vp8/common/x86/vp8_asm_stubs.c
@@ -0,0 +1,342 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "vpx_ports/mem.h" +#include "subpixel.h" + +extern const short vp8_six_tap_mmx[8][6*8]; +extern const short vp8_bilinear_filters_mmx[8][2*8]; + +extern void vp8_filter_block1d_h6_mmx +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1dc_v6_mmx +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int output_pitch, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d8_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d16_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_filter_block1d8_v6_sse2 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int dst_ptich, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const short *vp8_filter +); +extern void vp8_unpack_block1d16_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_height, + unsigned int output_width +); +extern void vp8_unpack_block1d8_h6_sse2 +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int output_height, + unsigned int output_width +); +extern void vp8_pack_block1d8_v6_sse2 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int dst_ptich, + unsigned int pixels_per_line, + unsigned int output_height, + unsigned int output_width +); +extern void vp8_pack_block1d16_v6_sse2 +( + unsigned short *src_ptr, + unsigned char *output_ptr, + int dst_ptich, + unsigned int pixels_per_line, + unsigned int output_height, + unsigned int output_width +); +extern prototype_subpixel_predict(vp8_bilinear_predict8x8_mmx); + + +#if HAVE_MMX +void vp8_sixtap_predict4x4_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 16*16); // Temp data bufffer used in filtering + const short *HFilter, *VFilter; + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 8, HFilter); + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 8, dst_ptr, dst_pitch, 8, 4 , 4, 4, VFilter); + +} + + +void vp8_sixtap_predict16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); // Temp data bufffer used in filtering + + const short *HFilter, *VFilter; + + + HFilter = vp8_six_tap_mmx[xoffset]; + + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 8, FData2 + 8, src_pixels_per_line, 1, 21, 32, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 12, FData2 + 12, src_pixels_per_line, 1, 21, 32, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 32, dst_ptr, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 36, dst_ptr + 4, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 40, dst_ptr + 8, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 44, dst_ptr + 12, dst_pitch, 32, 16 , 16, 16, VFilter); + +} + + +void vp8_sixtap_predict8x8_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); // Temp data bufffer used in filtering + + const short *HFilter, *VFilter; + + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 13, 16, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 13, 16, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 8, 8, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 20, dst_ptr + 4, dst_pitch, 16, 8 , 8, 8, VFilter); + +} + + +void vp8_sixtap_predict8x4_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); // Temp data bufffer used in filtering + + const short *HFilter, *VFilter; + + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 16, HFilter); + vp8_filter_block1d_h6_mmx(src_ptr - (2 * src_pixels_per_line) + 4, FData2 + 4, src_pixels_per_line, 1, 9, 16, HFilter); + + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1dc_v6_mmx(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 4, 8, VFilter); + vp8_filter_block1dc_v6_mmx(FData2 + 20, dst_ptr + 4, dst_pitch, 16, 8 , 4, 8, VFilter); + +} + + + +void vp8_bilinear_predict16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + vp8_bilinear_predict8x8_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8, src_pixels_per_line, xoffset, yoffset, dst_ptr + 8, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8 * src_pixels_per_line, src_pixels_per_line, xoffset, yoffset, dst_ptr + dst_pitch * 8, dst_pitch); + vp8_bilinear_predict8x8_mmx(src_ptr + 8 * src_pixels_per_line + 8, src_pixels_per_line, xoffset, yoffset, dst_ptr + dst_pitch * 8 + 8, dst_pitch); +} +#endif + + +#if HAVE_SSE2 +void vp8_sixtap_predict16x16_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch + +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 24*24); // Temp data bufffer used in filtering + + const short *HFilter, *VFilter; + + if (xoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d16_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 21, 32, HFilter); + } + else + { + vp8_unpack_block1d16_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 21, 32); + } + + if (yoffset) + { + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_sse2(FData2 + 32, dst_ptr, dst_pitch, 32, 16 , 16, 16, VFilter); + vp8_filter_block1d8_v6_sse2(FData2 + 40, dst_ptr + 8, dst_pitch, 32, 16 , 16, 16, VFilter); + } + else + { + vp8_pack_block1d16_v6_sse2(FData2 + 32, dst_ptr, dst_pitch, 32, 16, 16); + } +} + + +void vp8_sixtap_predict8x8_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); // Temp data bufffer used in filtering + const short *HFilter, *VFilter; + + if (xoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 13, 16, HFilter); + } + else + { + vp8_unpack_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 13, 16); + } + + if (yoffset) + { + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 8, dst_pitch, VFilter); + } + else + { + vp8_pack_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 8, dst_pitch); + } + + +} + + +void vp8_sixtap_predict8x4_sse2 +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pitch +) +{ + DECLARE_ALIGNED_ARRAY(16, unsigned short, FData2, 256); // Temp data bufffer used in filtering + const short *HFilter, *VFilter; + + if (xoffset) + { + HFilter = vp8_six_tap_mmx[xoffset]; + vp8_filter_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 1, 9, 16, HFilter); + } + else + { + vp8_unpack_block1d8_h6_sse2(src_ptr - (2 * src_pixels_per_line), FData2, src_pixels_per_line, 9, 16); + } + + if (yoffset) + { + VFilter = vp8_six_tap_mmx[yoffset]; + vp8_filter_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 8 , 4, dst_pitch, VFilter); + } + else + { + vp8_pack_block1d8_v6_sse2(FData2 + 16, dst_ptr, dst_pitch, 16, 4, dst_pitch); + } + + +} +#endif
diff --git a/vp8/common/x86/x86_systemdependent.c b/vp8/common/x86/x86_systemdependent.c new file mode 100644 index 0000000..5312e06 --- /dev/null +++ b/vp8/common/x86/x86_systemdependent.c
@@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "vpx_ports/x86.h" +#include "g_common.h" +#include "subpixel.h" +#include "loopfilter.h" +#include "recon.h" +#include "idct.h" +#include "pragmas.h" +#include "onyxc_int.h" + +void vp8_arch_x86_common_init(VP8_COMMON *ctx) +{ +#if CONFIG_RUNTIME_CPU_DETECT + VP8_COMMON_RTCD *rtcd = &ctx->rtcd; + int flags = x86_simd_caps(); + int mmx_enabled = flags & HAS_MMX; + int xmm_enabled = flags & HAS_SSE; + int wmt_enabled = flags & HAS_SSE2; + + /* Note: + * + * This platform can be built without runtime CPU detection as well. If + * you modify any of the function mappings present in this file, be sure + * to also update them in static mapings (<arch>/filename_<arch>.h) + */ + + /* Override default functions with fastest ones for this CPU. */ +#if HAVE_MMX + + if (mmx_enabled) + { + rtcd->idct.idct1 = vp8_short_idct4x4llm_1_mmx; + rtcd->idct.idct16 = vp8_short_idct4x4llm_mmx; + rtcd->idct.idct1_scalar = vp8_dc_only_idct_mmx; + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_mmx; + rtcd->idct.iwalsh1 = vp8_short_inv_walsh4x4_1_mmx; + + + + rtcd->recon.recon = vp8_recon_b_mmx; + rtcd->recon.copy8x8 = vp8_copy_mem8x8_mmx; + rtcd->recon.copy8x4 = vp8_copy_mem8x4_mmx; + rtcd->recon.copy16x16 = vp8_copy_mem16x16_mmx; + + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_mmx; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_mmx; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_mmx; + rtcd->subpix.sixtap4x4 = vp8_sixtap_predict4x4_mmx; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_mmx; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_mmx; + rtcd->subpix.bilinear8x4 = vp8_bilinear_predict8x4_mmx; + rtcd->subpix.bilinear4x4 = vp8_bilinear_predict4x4_mmx; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_mmx; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_mmx; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_mmx; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_mmx; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_mmx; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_mmx; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_mmx; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_mmx; + +#if CONFIG_POSTPROC + rtcd->postproc.down = vp8_mbpost_proc_down_mmx; + //rtcd->postproc.across = vp8_mbpost_proc_across_ip_c; + rtcd->postproc.downacross = vp8_post_proc_down_and_across_mmx; + rtcd->postproc.addnoise = vp8_plane_add_noise_mmx; +#endif + } + +#endif +#if HAVE_SSE2 + + if (wmt_enabled) + { + rtcd->recon.recon2 = vp8_recon2b_sse2; + rtcd->recon.recon4 = vp8_recon4b_sse2; + rtcd->recon.copy16x16 = vp8_copy_mem16x16_sse2; + + rtcd->idct.iwalsh16 = vp8_short_inv_walsh4x4_sse2; + + rtcd->subpix.sixtap16x16 = vp8_sixtap_predict16x16_sse2; + rtcd->subpix.sixtap8x8 = vp8_sixtap_predict8x8_sse2; + rtcd->subpix.sixtap8x4 = vp8_sixtap_predict8x4_sse2; + rtcd->subpix.bilinear16x16 = vp8_bilinear_predict16x16_sse2; + rtcd->subpix.bilinear8x8 = vp8_bilinear_predict8x8_sse2; + + rtcd->loopfilter.normal_mb_v = vp8_loop_filter_mbv_sse2; + rtcd->loopfilter.normal_b_v = vp8_loop_filter_bv_sse2; + rtcd->loopfilter.normal_mb_h = vp8_loop_filter_mbh_sse2; + rtcd->loopfilter.normal_b_h = vp8_loop_filter_bh_sse2; + rtcd->loopfilter.simple_mb_v = vp8_loop_filter_mbvs_sse2; + rtcd->loopfilter.simple_b_v = vp8_loop_filter_bvs_sse2; + rtcd->loopfilter.simple_mb_h = vp8_loop_filter_mbhs_sse2; + rtcd->loopfilter.simple_b_h = vp8_loop_filter_bhs_sse2; + +#if CONFIG_POSTPROC + rtcd->postproc.down = vp8_mbpost_proc_down_xmm; + rtcd->postproc.across = vp8_mbpost_proc_across_ip_xmm; + rtcd->postproc.downacross = vp8_post_proc_down_and_across_xmm; + rtcd->postproc.addnoise = vp8_plane_add_noise_wmt; +#endif + } + +#endif +#endif +}
diff --git a/vp8/decoder/arm/armv5/dequantize_v5.asm b/vp8/decoder/arm/armv5/dequantize_v5.asm new file mode 100644 index 0000000..eb3f030 --- /dev/null +++ b/vp8/decoder/arm/armv5/dequantize_v5.asm
@@ -0,0 +1,51 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequantize_b_armv5| + + AREA |.text|, CODE, READONLY ; name this block of code + +q RN r0 +dqc RN r1 +cnt RN r2 + +;void dequantize_b_armv5(short *Q, short *DQC) +|vp8_dequantize_b_armv5| PROC + stmdb sp!, {r4, lr} + ldr r3, [q] + ldr r4, [dqc], #8 + + mov cnt, #4 +dequant_loop + smulbb lr, r3, r4 + smultt r12, r3, r4 + + ldr r3, [q, #4] + ldr r4, [dqc, #-4] + + strh lr, [q], #2 + strh r12, [q], #2 + + smulbb lr, r3, r4 + smultt r12, r3, r4 + + subs cnt, cnt, #1 + ldrne r3, [q, #4] + ldrne r4, [dqc], #8 + + strh lr, [q], #2 + strh r12, [q], #2 + + bne dequant_loop + + ldmia sp!, {r4, pc} + ENDP ;|vp8_dequantize_b_arm| + + END
diff --git a/vp8/decoder/arm/armv6/dboolhuff_v6.asm b/vp8/decoder/arm/armv6/dboolhuff_v6.asm new file mode 100644 index 0000000..143e33e --- /dev/null +++ b/vp8/decoder/arm/armv6/dboolhuff_v6.asm
@@ -0,0 +1,162 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_decode_value_v6| + EXPORT |vp8dx_start_decode_v6| + EXPORT |vp8dx_stop_decode_v6| + EXPORT |vp8dx_decode_bool_v6| + + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE vpx_asm_offsets.asm + +br RN r0 +prob RN r1 +bits RN r1 + AREA |.text|, CODE, READONLY ; name this block of code + +; int z = 0; +; int bit; +; for ( bit=bits-1; bit>=0; bit-- ) +; { +; z |= (vp8dx_decode_bool(br, 0x80)<<bit); +; } +; return z; + +;int vp8_decode_value_v6 ( BOOL_DECODER *br, int bits ) +|vp8_decode_value_v6| PROC + stmdb sp!, {r4 - r6, lr} + mov r4, br + mov r5, bits + mov r6, #0 + + subs r5, r5, #1 + bmi decode_value_exit + +decode_value_loop + mov prob, #0x80 + mov br, r4 + bl vp8dx_decode_bool_v6_internal ; needed for conversion to s file + orr r6, r6, r0, lsl r5 + subs r5, r5, #1 + bpl decode_value_loop + +decode_value_exit + mov r0, r6 + ldmia sp!, {r4 - r6, pc} + ENDP ; |vp8_decode_value_v6| + + +;void vp8dx_start_decode_v6 ( BOOL_DECODER *br, unsigned char *source ) +|vp8dx_start_decode_v6| PROC + stmdb sp!, {r4 - r5, lr} + mov r2, #0 + mov r3, #255 + + str r2, [br, #bool_decoder_lowvalue] + str r3, [br, #bool_decoder_range] + str r1, [br, #bool_decoder_buffer] + + mov r3, #8 + mov r2, #4 + str r3, [br, #bool_decoder_count] + str r2, [br, #bool_decoder_pos] + + ldrb r2, [r1, #3] + ldrb r3, [r1, #2] + ldrb r4, [r1, #1] + ldrb r5, [r1] + + orr r1, r2, r3, lsl #8 + orr r1, r1, r4, lsl #16 + orr r1, r1, r5, lsl #24 + + str r1, [br, #bool_decoder_value] + + ldmia sp!, {r4 - r5, pc} + ENDP ; |vp8dx_start_decode_v6| + + +;void vp8dx_stop_decode_v6 ( BOOL_DECODER *bc ); +|vp8dx_stop_decode_v6| PROC + mov pc, lr + ENDP ; |vp8dx_stop_decode_v6| + + +; bigsplit RN r1 +; buffer_v RN r1 +; count_v RN r4 +; range_v RN r2 +; value_v RN r3 +; pos_v RN r5 +; split RN r6 +; bit RN lr +;int vp8dx_decode_bool_v6 ( BOOL_DECODER *br, int probability ) +|vp8dx_decode_bool_v6| PROC +vp8dx_decode_bool_v6_internal + stmdb sp!, {r4 - r6, lr} + + ldr r2, [br, #bool_decoder_range] + ldr r3, [br, #bool_decoder_value] + + mov r6, r2, lsl #8 + sub r6, r6, #256 ; split = 1 + (((range-1) * probability) >> 8) + mov r12, #1 + smlawb r6, r6, prob, r12 + + mov lr, #0 + subs r5, r3, r6, lsl #24 + + ;cmp r3, r1 + movhs lr, #1 + movhs r3, r5 + subhs r2, r2, r6 + movlo r2, r6 + + cmp r2, #0x80 + blt range_less_0x80 + ;strd r2, r3, [br, #bool_decoder_range] + str r2, [br, #bool_decoder_range] + str r3, [br, #bool_decoder_value] + mov r0, lr + ldmia sp!, {r4 - r6, pc} + +range_less_0x80 + ldr r5, [br, #bool_decoder_pos] + ldr r1, [br, #bool_decoder_buffer] + ldr r4, [br, #bool_decoder_count] + add r1, r1, r5 + + clz r12, r2 + sub r12, r12, #24 + subs r4, r4, r12 + ldrleb r6, [r1], #1 + mov r2, r2, lsl r12 + mov r3, r3, lsl r12 + addle r4, r4, #8 + rsble r12, r4, #8 + addle r5, r5, #1 + orrle r3, r3, r6, lsl r12 + + ;strd r2, r3, [br, #bool_decoder_range] + ;strd r4, r5, [br, #bool_decoder_count] + str r2, [br, #bool_decoder_range] + str r3, [br, #bool_decoder_value] + str r4, [br, #bool_decoder_count] + str r5, [br, #bool_decoder_pos] + + mov r0, lr + + ldmia sp!, {r4 - r6, pc} + ENDP ; |vp8dx_decode_bool_v6| + + END
diff --git a/vp8/decoder/arm/armv6/dequantdcidct_v6.asm b/vp8/decoder/arm/armv6/dequantdcidct_v6.asm new file mode 100644 index 0000000..3daa9b3 --- /dev/null +++ b/vp8/decoder/arm/armv6/dequantdcidct_v6.asm
@@ -0,0 +1,202 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequant_dc_idct_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code +;void vp8_dequant_dc_idct_v6(short *input, short *dq, short *output, int pitch,int Dc) +|vp8_dequant_dc_idct_v6| PROC + stmdb sp!, {r4-r11, lr} + + ldr r6, [sp, #36] ;load Dc + + ldr r4, [r0] ;input + ldr r5, [r1], #4 ;dq + + sub sp, sp, #4 + str r0, [sp] + + smultt r7, r4, r5 + + ldr r4, [r0, #4] ;input + ldr r5, [r1], #4 ;dq + + strh r6, [r0], #2 + strh r7, [r0], #2 + + smulbb r6, r4, r5 + smultt r7, r4, r5 + + ldr r4, [r0, #4] ;input + ldr r5, [r1], #4 ;dq + + strh r6, [r0], #2 + strh r7, [r0], #2 + + mov r12, #3 + +dequant_dc_idct_loop + smulbb r6, r4, r5 + smultt r7, r4, r5 + + ldr r4, [r0, #4] ;input + ldr r5, [r1], #4 ;dq + + strh r6, [r0], #2 + strh r7, [r0], #2 + + smulbb r6, r4, r5 + smultt r7, r4, r5 + + subs r12, r12, #1 + + ldrne r4, [r0, #4] + ldrne r5, [r1], #4 + + strh r6, [r0], #2 + strh r7, [r0], #2 + + bne dequant_dc_idct_loop + + sub r0, r0, #32 + mov r1, r2 + mov r2, r3 + +; short_idct4x4llm_v6_dual + + mov r3, #0x00004E00 ; cos + orr r3, r3, #0x0000007B ; cospi8sqrt2minus1 + mov r4, #0x00008A00 ; sin + orr r4, r4, #0x0000008C ; sinpi8sqrt2 + mov r5, #0x2 ; i=2 i +loop1_dual_11 + ldr r6, [r0, #(4*2)] ; i5 | i4 5|4 + ldr r12, [r0, #(12*2)] ; i13 | i12 13|12 + ldr r14, [r0, #(8*2)] ; i9 | i8 9|8 + + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwb r7, r3, r6 ; (ip[4] * cospi8sqrt2minus1) >> 16 4c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwb r8, r4, r6 ; (ip[4] * sinpi8sqrt2) >> 16 4s + pkhbt r7, r7, r9, lsl #16 ; 5c | 4c + smulwt r11, r3, r12 ; (ip[13] * cospi8sqrt2minus1) >> 16 13c + pkhbt r8, r8, r10, lsl #16 ; 5s | 4s + uadd16 r6, r6, r7 ; 5c+5 | 4c+4 + smulwt r7, r4, r12 ; (ip[13] * sinpi8sqrt2) >> 16 13s + smulwb r9, r3, r12 ; (ip[12] * cospi8sqrt2minus1) >> 16 12c + smulwb r10, r4, r12 ; (ip[12] * sinpi8sqrt2) >> 16 12s + subs r5, r5, #0x1 ; i-- -- + pkhbt r9, r9, r11, lsl #16 ; 13c | 12c + ldr r11, [r0], #0x4 ; i1 | i0 ++ 1|0 + pkhbt r10, r10, r7, lsl #16 ; 13s | 12s + uadd16 r7, r12, r9 ; 13c+13 | 12c+12 + usub16 r7, r8, r7 ; c c + uadd16 r6, r6, r10 ; d d + uadd16 r10, r11, r14 ; a a + usub16 r8, r11, r14 ; b b + uadd16 r9, r10, r6 ; a+d a+d + usub16 r10, r10, r6 ; a-d a-d + uadd16 r6, r8, r7 ; b+c b+c + usub16 r7, r8, r7 ; b-c b-c + str r6, [r1, r2] ; o5 | o4 + add r6, r2, r2 ; pitch * 2 p2 + str r7, [r1, r6] ; o9 | o8 + add r6, r6, r2 ; pitch * 3 p3 + str r10, [r1, r6] ; o13 | o12 + str r9, [r1], #0x4 ; o1 | o0 ++ + bne loop1_dual_11 ; + mov r5, #0x2 ; i=2 i + sub r0, r1, #8 ; reset input/output i/o +loop2_dual_22 + ldr r6, [r0, r2] ; i5 | i4 5|4 + ldr r1, [r0] ; i1 | i0 1|0 + ldr r12, [r0, #0x4] ; i3 | i2 3|2 + add r14, r2, #0x4 ; pitch + 2 p+2 + ldr r14, [r0, r14] ; i7 | i6 7|6 + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwt r7, r3, r1 ; (ip[1] * cospi8sqrt2minus1) >> 16 1c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwt r8, r4, r1 ; (ip[1] * sinpi8sqrt2) >> 16 1s + pkhbt r11, r6, r1, lsl #16 ; i0 | i4 0|4 + pkhbt r7, r9, r7, lsl #16 ; 1c | 5c + pkhbt r8, r10, r8, lsl #16 ; 1s | 5s = temp1 © tc1 + pkhtb r1, r1, r6, asr #16 ; i1 | i5 1|5 + uadd16 r1, r7, r1 ; 1c+1 | 5c+5 = temp2 (d) td2 + pkhbt r9, r14, r12, lsl #16 ; i2 | i6 2|6 + uadd16 r10, r11, r9 ; a a + usub16 r9, r11, r9 ; b b + pkhtb r6, r12, r14, asr #16 ; i3 | i7 3|7 + subs r5, r5, #0x1 ; i-- -- + smulwt r7, r3, r6 ; (ip[3] * cospi8sqrt2minus1) >> 16 3c + smulwt r11, r4, r6 ; (ip[3] * sinpi8sqrt2) >> 16 3s + smulwb r12, r3, r6 ; (ip[7] * cospi8sqrt2minus1) >> 16 7c + smulwb r14, r4, r6 ; (ip[7] * sinpi8sqrt2) >> 16 7s + + pkhbt r7, r12, r7, lsl #16 ; 3c | 7c + pkhbt r11, r14, r11, lsl #16 ; 3s | 7s = temp1 (d) td1 + uadd16 r6, r7, r6 ; 3c+3 | 7c+7 = temp2 (c) tc2 + usub16 r12, r8, r6 ; c (o1 | o5) c + uadd16 r6, r11, r1 ; d (o3 | o7) d + uadd16 r7, r10, r6 ; a+d a+d + mov r8, #0x4 ; set up 4's 4 + orr r8, r8, #0x40000 ; 4|4 + usub16 r6, r10, r6 ; a-d a-d + uadd16 r6, r6, r8 ; a-d+4 3|7 + uadd16 r7, r7, r8 ; a+d+4 0|4 + uadd16 r10, r9, r12 ; b+c b+c + usub16 r1, r9, r12 ; b-c b-c + uadd16 r10, r10, r8 ; b+c+4 1|5 + uadd16 r1, r1, r8 ; b-c+4 2|6 + mov r8, r10, asr #19 ; o1 >> 3 + strh r8, [r0, #2] ; o1 + mov r8, r1, asr #19 ; o2 >> 3 + strh r8, [r0, #4] ; o2 + mov r8, r6, asr #19 ; o3 >> 3 + strh r8, [r0, #6] ; o3 + mov r8, r7, asr #19 ; o0 >> 3 + strh r8, [r0], r2 ; o0 +p + sxth r10, r10 ; + mov r8, r10, asr #3 ; o5 >> 3 + strh r8, [r0, #2] ; o5 + sxth r1, r1 ; + mov r8, r1, asr #3 ; o6 >> 3 + strh r8, [r0, #4] ; o6 + sxth r6, r6 ; + mov r8, r6, asr #3 ; o7 >> 3 + strh r8, [r0, #6] ; o7 + sxth r7, r7 ; + mov r8, r7, asr #3 ; o4 >> 3 + strh r8, [r0], r2 ; o4 +p +;;;;; subs r5, r5, #0x1 ; i-- -- + bne loop2_dual_22 ; + + +;vpx_memset + ldr r0, [sp] + add sp, sp, #4 + + mov r12, #0 + str r12, [r0] + str r12, [r0, #4] + str r12, [r0, #8] + str r12, [r0, #12] + str r12, [r0, #16] + str r12, [r0, #20] + str r12, [r0, #24] + str r12, [r0, #28] + + ldmia sp!, {r4 - r11, pc} ; replace vars, return restore + + ENDP ;|vp8_dequant_dc_idct_v68| + + END
diff --git a/vp8/decoder/arm/armv6/dequantidct_v6.asm b/vp8/decoder/arm/armv6/dequantidct_v6.asm new file mode 100644 index 0000000..61bb48d --- /dev/null +++ b/vp8/decoder/arm/armv6/dequantidct_v6.asm
@@ -0,0 +1,183 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequant_idct_v6| + ; ARM + ; REQUIRE8 + ; PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code +;void vp8_dequant_idct_v6(short *input, short *dq, short *output, int pitch) +|vp8_dequant_idct_v6| PROC + stmdb sp!, {r4-r11, lr} + + ldr r4, [r0] ;input + ldr r5, [r1], #4 ;dq + + sub sp, sp, #4 + str r0, [sp] + + mov r12, #4 + +dequant_idct_loop + smulbb r6, r4, r5 + smultt r7, r4, r5 + + ldr r4, [r0, #4] ;input + ldr r5, [r1], #4 ;dq + + strh r6, [r0], #2 + strh r7, [r0], #2 + + smulbb r6, r4, r5 + smultt r7, r4, r5 + + subs r12, r12, #1 + + ldrne r4, [r0, #4] + ldrne r5, [r1], #4 + + strh r6, [r0], #2 + strh r7, [r0], #2 + + bne dequant_idct_loop + + sub r0, r0, #32 + mov r1, r2 + mov r2, r3 + +; short_idct4x4llm_v6_dual + + mov r3, #0x00004E00 ; cos + orr r3, r3, #0x0000007B ; cospi8sqrt2minus1 + mov r4, #0x00008A00 ; sin + orr r4, r4, #0x0000008C ; sinpi8sqrt2 + mov r5, #0x2 ; i=2 i +loop1_dual_1 + ldr r6, [r0, #(4*2)] ; i5 | i4 5|4 + ldr r12, [r0, #(12*2)] ; i13 | i12 13|12 + ldr r14, [r0, #(8*2)] ; i9 | i8 9|8 + + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwb r7, r3, r6 ; (ip[4] * cospi8sqrt2minus1) >> 16 4c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwb r8, r4, r6 ; (ip[4] * sinpi8sqrt2) >> 16 4s + pkhbt r7, r7, r9, lsl #16 ; 5c | 4c + smulwt r11, r3, r12 ; (ip[13] * cospi8sqrt2minus1) >> 16 13c + pkhbt r8, r8, r10, lsl #16 ; 5s | 4s + uadd16 r6, r6, r7 ; 5c+5 | 4c+4 + smulwt r7, r4, r12 ; (ip[13] * sinpi8sqrt2) >> 16 13s + smulwb r9, r3, r12 ; (ip[12] * cospi8sqrt2minus1) >> 16 12c + smulwb r10, r4, r12 ; (ip[12] * sinpi8sqrt2) >> 16 12s + subs r5, r5, #0x1 ; i-- -- + pkhbt r9, r9, r11, lsl #16 ; 13c | 12c + ldr r11, [r0], #0x4 ; i1 | i0 ++ 1|0 + pkhbt r10, r10, r7, lsl #16 ; 13s | 12s + uadd16 r7, r12, r9 ; 13c+13 | 12c+12 + usub16 r7, r8, r7 ; c c + uadd16 r6, r6, r10 ; d d + uadd16 r10, r11, r14 ; a a + usub16 r8, r11, r14 ; b b + uadd16 r9, r10, r6 ; a+d a+d + usub16 r10, r10, r6 ; a-d a-d + uadd16 r6, r8, r7 ; b+c b+c + usub16 r7, r8, r7 ; b-c b-c + str r6, [r1, r2] ; o5 | o4 + add r6, r2, r2 ; pitch * 2 p2 + str r7, [r1, r6] ; o9 | o8 + add r6, r6, r2 ; pitch * 3 p3 + str r10, [r1, r6] ; o13 | o12 + str r9, [r1], #0x4 ; o1 | o0 ++ + bne loop1_dual_1 ; + mov r5, #0x2 ; i=2 i + sub r0, r1, #8 ; reset input/output i/o +loop2_dual_2 + ldr r6, [r0, r2] ; i5 | i4 5|4 + ldr r1, [r0] ; i1 | i0 1|0 + ldr r12, [r0, #0x4] ; i3 | i2 3|2 + add r14, r2, #0x4 ; pitch + 2 p+2 + ldr r14, [r0, r14] ; i7 | i6 7|6 + smulwt r9, r3, r6 ; (ip[5] * cospi8sqrt2minus1) >> 16 5c + smulwt r7, r3, r1 ; (ip[1] * cospi8sqrt2minus1) >> 16 1c + smulwt r10, r4, r6 ; (ip[5] * sinpi8sqrt2) >> 16 5s + smulwt r8, r4, r1 ; (ip[1] * sinpi8sqrt2) >> 16 1s + pkhbt r11, r6, r1, lsl #16 ; i0 | i4 0|4 + pkhbt r7, r9, r7, lsl #16 ; 1c | 5c + pkhbt r8, r10, r8, lsl #16 ; 1s | 5s = temp1 © tc1 + pkhtb r1, r1, r6, asr #16 ; i1 | i5 1|5 + uadd16 r1, r7, r1 ; 1c+1 | 5c+5 = temp2 (d) td2 + pkhbt r9, r14, r12, lsl #16 ; i2 | i6 2|6 + uadd16 r10, r11, r9 ; a a + usub16 r9, r11, r9 ; b b + pkhtb r6, r12, r14, asr #16 ; i3 | i7 3|7 + subs r5, r5, #0x1 ; i-- -- + smulwt r7, r3, r6 ; (ip[3] * cospi8sqrt2minus1) >> 16 3c + smulwt r11, r4, r6 ; (ip[3] * sinpi8sqrt2) >> 16 3s + smulwb r12, r3, r6 ; (ip[7] * cospi8sqrt2minus1) >> 16 7c + smulwb r14, r4, r6 ; (ip[7] * sinpi8sqrt2) >> 16 7s + + pkhbt r7, r12, r7, lsl #16 ; 3c | 7c + pkhbt r11, r14, r11, lsl #16 ; 3s | 7s = temp1 (d) td1 + uadd16 r6, r7, r6 ; 3c+3 | 7c+7 = temp2 (c) tc2 + usub16 r12, r8, r6 ; c (o1 | o5) c + uadd16 r6, r11, r1 ; d (o3 | o7) d + uadd16 r7, r10, r6 ; a+d a+d + mov r8, #0x4 ; set up 4's 4 + orr r8, r8, #0x40000 ; 4|4 + usub16 r6, r10, r6 ; a-d a-d + uadd16 r6, r6, r8 ; a-d+4 3|7 + uadd16 r7, r7, r8 ; a+d+4 0|4 + uadd16 r10, r9, r12 ; b+c b+c + usub16 r1, r9, r12 ; b-c b-c + uadd16 r10, r10, r8 ; b+c+4 1|5 + uadd16 r1, r1, r8 ; b-c+4 2|6 + mov r8, r10, asr #19 ; o1 >> 3 + strh r8, [r0, #2] ; o1 + mov r8, r1, asr #19 ; o2 >> 3 + strh r8, [r0, #4] ; o2 + mov r8, r6, asr #19 ; o3 >> 3 + strh r8, [r0, #6] ; o3 + mov r8, r7, asr #19 ; o0 >> 3 + strh r8, [r0], r2 ; o0 +p + sxth r10, r10 ; + mov r8, r10, asr #3 ; o5 >> 3 + strh r8, [r0, #2] ; o5 + sxth r1, r1 ; + mov r8, r1, asr #3 ; o6 >> 3 + strh r8, [r0, #4] ; o6 + sxth r6, r6 ; + mov r8, r6, asr #3 ; o7 >> 3 + strh r8, [r0, #6] ; o7 + sxth r7, r7 ; + mov r8, r7, asr #3 ; o4 >> 3 + strh r8, [r0], r2 ; o4 +p +;;;;; subs r5, r5, #0x1 ; i-- -- + bne loop2_dual_2 ; + ; + +;vpx_memset + ldr r0, [sp] + add sp, sp, #4 + + mov r12, #0 + str r12, [r0] + str r12, [r0, #4] + str r12, [r0, #8] + str r12, [r0, #12] + str r12, [r0, #16] + str r12, [r0, #20] + str r12, [r0, #24] + str r12, [r0, #28] + + ldmia sp!, {r4 - r11, pc} ; replace vars, return restore + + ENDP ;|vp8_dequant_idct_v6| + + END
diff --git a/vp8/decoder/arm/armv6/dequantize_v6.asm b/vp8/decoder/arm/armv6/dequantize_v6.asm new file mode 100644 index 0000000..95e3859 --- /dev/null +++ b/vp8/decoder/arm/armv6/dequantize_v6.asm
@@ -0,0 +1,68 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequantize_b_loop_v6| + + AREA |.text|, CODE, READONLY ; name this block of code +;------------------------------- +;void vp8_dequantize_b_loop_v6(short *Q, short *DQC, short *DQ); +; r0 short *Q, +; r1 short *DQC +; r2 short *DQ +|vp8_dequantize_b_loop_v6| PROC + stmdb sp!, {r4-r9, lr} + + ldr r3, [r0] ;load Q + ldr r4, [r1] ;load DQC + ldr r5, [r0, #4] + ldr r6, [r1, #4] + + mov r12, #2 ;loop counter + +dequant_loop + smulbb r7, r3, r4 ;multiply + smultt r8, r3, r4 + smulbb r9, r5, r6 + smultt lr, r5, r6 + + ldr r3, [r0, #8] + ldr r4, [r1, #8] + ldr r5, [r0, #12] + ldr r6, [r1, #12] + + strh r7, [r2], #2 ;store result + smulbb r7, r3, r4 ;multiply + strh r8, [r2], #2 + smultt r8, r3, r4 + strh r9, [r2], #2 + smulbb r9, r5, r6 + strh lr, [r2], #2 + smultt lr, r5, r6 + + subs r12, r12, #1 + + add r0, r0, #16 + add r1, r1, #16 + + ldrne r3, [r0] + strh r7, [r2], #2 ;store result + ldrne r4, [r1] + strh r8, [r2], #2 + ldrne r5, [r0, #4] + strh r9, [r2], #2 + ldrne r6, [r1, #4] + strh lr, [r2], #2 + + bne dequant_loop + + ldmia sp!, {r4-r9, pc} + ENDP ;|vp8_dequantize_b_loop_v6| + + END
diff --git a/vp8/decoder/arm/dboolhuff_arm.h b/vp8/decoder/arm/dboolhuff_arm.h new file mode 100644 index 0000000..495004f --- /dev/null +++ b/vp8/decoder/arm/dboolhuff_arm.h
@@ -0,0 +1,49 @@ +#ifndef DBOOLHUFF_ARM_H +#define DBOOLHUFF_ARM_H + +/* JLK + * There are currently no arm-optimized versions of + * these functions. As they are implemented, they + * can be uncommented below and added to + * arm/dsystemdependent.c + * + * The existing asm code is likely so different as + * to be useless. However, its been left (for now) + * for reference. + */ +/* +#if HAVE_ARMV6 +#undef vp8_dbool_start +#define vp8_dbool_start vp8dx_start_decode_v6 + +#undef vp8_dbool_stop +#define vp8_dbool_stop vp8dx_stop_decode_v6 + +#undef vp8_dbool_fill +#define vp8_dbool_fill vp8_bool_decoder_fill_v6 + +#undef vp8_dbool_debool +#define vp8_dbool_debool vp8_decode_bool_v6 + +#undef vp8_dbool_devalue +#define vp8_dbool_devalue vp8_decode_value_v6 +#endif // HAVE_ARMV6 + +#if HAVE_ARMV7 +#undef vp8_dbool_start +#define vp8_dbool_start vp8dx_start_decode_neon + +#undef vp8_dbool_stop +#define vp8_dbool_stop vp8dx_stop_decode_neon + +#undef vp8_dbool_fill +#define vp8_dbool_fill vp8_bool_decoder_fill_neon + +#undef vp8_dbool_debool +#define vp8_dbool_debool vp8_decode_bool_neon + +#undef vp8_dbool_devalue +#define vp8_dbool_devalue vp8_decode_value_neon +#endif // HAVE_ARMV7 +*/ +#endif // DBOOLHUFF_ARM_H
diff --git a/vp8/decoder/arm/dequantize_arm.c b/vp8/decoder/arm/dequantize_arm.c new file mode 100644 index 0000000..54006a9 --- /dev/null +++ b/vp8/decoder/arm/dequantize_arm.c
@@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "dequantize.h" +#include "predictdc.h" +#include "idct.h" +#include "vpx_mem/vpx_mem.h" + +#if HAVE_ARMV7 +extern void vp8_dequantize_b_loop_neon(short *Q, short *DQC, short *DQ); +#endif + +#if HAVE_ARMV6 +extern void vp8_dequantize_b_loop_v6(short *Q, short *DQC, short *DQ); +#endif + +#if HAVE_ARMV7 + +void vp8_dequantize_b_neon(BLOCKD *d) +{ + int i; + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + short *DQC = &d->dequant[0][0]; + + vp8_dequantize_b_loop_neon(Q, DQC, DQ); +} +#endif + +#if HAVE_ARMV6 +void vp8_dequantize_b_v6(BLOCKD *d) +{ + int i; + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + short *DQC = &d->dequant[0][0]; + + vp8_dequantize_b_loop_v6(Q, DQC, DQ); +} +#endif
diff --git a/vp8/decoder/arm/dequantize_arm.h b/vp8/decoder/arm/dequantize_arm.h new file mode 100644 index 0000000..c8a61a4 --- /dev/null +++ b/vp8/decoder/arm/dequantize_arm.h
@@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DEQUANTIZE_ARM_H +#define DEQUANTIZE_ARM_H + +#if HAVE_ARMV6 +extern prototype_dequant_block(vp8_dequantize_b_v6); +extern prototype_dequant_idct(vp8_dequant_idct_v6); +extern prototype_dequant_idct_dc(vp8_dequant_dc_idct_v6); + +#undef vp8_dequant_block +#define vp8_dequant_block vp8_dequantize_b_v6 + +#undef vp8_dequant_idct +#define vp8_dequant_idct vp8_dequant_idct_v6 + +#undef vp8_dequant_idct_dc +#define vp8_dequant_idct_dc vp8_dequant_dc_idct_v6 +#endif + +#if HAVE_ARMV7 +extern prototype_dequant_block(vp8_dequantize_b_neon); +extern prototype_dequant_idct(vp8_dequant_idct_neon); +extern prototype_dequant_idct_dc(vp8_dequant_dc_idct_neon); + +#undef vp8_dequant_block +#define vp8_dequant_block vp8_dequantize_b_neon + +#undef vp8_dequant_idct +#define vp8_dequant_idct vp8_dequant_idct_neon + +#undef vp8_dequant_idct_dc +#define vp8_dequant_idct_dc vp8_dequant_dc_idct_neon +#endif + +#endif
diff --git a/vp8/decoder/arm/detokenizearm_sjl.c b/vp8/decoder/arm/detokenizearm_sjl.c new file mode 100644 index 0000000..c714452 --- /dev/null +++ b/vp8/decoder/arm/detokenizearm_sjl.c
@@ -0,0 +1,730 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "type_aliases.h" +#include "blockd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_ports/mem.h" + +#define BR_COUNT 8 +#define BOOL_DATA UINT8 + +#define OCB_X PREV_COEF_CONTEXTS * ENTROPY_NODES +//ALIGN16 UINT16 onyx_coef_bands_x[16] = { 0, 1*OCB_X, 2*OCB_X, 3*OCB_X, 6*OCB_X, 4*OCB_X, 5*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 6*OCB_X, 7*OCB_X}; +DECLARE_ALIGNED(16, UINT8, vp8_coef_bands_x[16]) = { 0, 1 * OCB_X, 2 * OCB_X, 3 * OCB_X, 6 * OCB_X, 4 * OCB_X, 5 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 7 * OCB_X}; + +#define EOB_CONTEXT_NODE 0 +#define ZERO_CONTEXT_NODE 1 +#define ONE_CONTEXT_NODE 2 +#define LOW_VAL_CONTEXT_NODE 3 +#define TWO_CONTEXT_NODE 4 +#define THREE_CONTEXT_NODE 5 +#define HIGH_LOW_CONTEXT_NODE 6 +#define CAT_ONE_CONTEXT_NODE 7 +#define CAT_THREEFOUR_CONTEXT_NODE 8 +#define CAT_THREE_CONTEXT_NODE 9 +#define CAT_FIVE_CONTEXT_NODE 10 + + + + +DECLARE_ALIGNED(16, static const TOKENEXTRABITS, vp8d_token_extra_bits2[MAX_ENTROPY_TOKENS]) = +{ + { 0, -1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //ZERO_TOKEN + { 1, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //ONE_TOKEN + { 2, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //TWO_TOKEN + { 3, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //THREE_TOKEN + { 4, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //FOUR_TOKEN + { 5, 0, { 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY1 + { 7, 1, { 145, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY2 + { 11, 2, { 140, 148, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY3 + { 19, 3, { 135, 140, 155, 176, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY4 + { 35, 4, { 130, 134, 141, 157, 180, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY5 + { 67, 10, { 129, 130, 133, 140, 153, 177, 196, 230, 243, 254, 254, 0 } }, //DCT_VAL_CATEGORY6 + { 0, -1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // EOB TOKEN +}; + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +DECLARE_ALIGNED(16, const UINT8, vp8_block2context_leftabove[25*3]) = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, //end of vp8_block2context + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 0, 0, 1, 1, 0, 0, 1, 1, 0, //end of vp8_block2left + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 0 //end of vp8_block2above +}; + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +void vp8_reset_mb_tokens_context(MACROBLOCKD *x) +{ + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + for (i = 0; i < 24; i++) + { + + a = A[ vp8_block2context[i] ] + vp8_block2above[i]; + l = L[ vp8_block2context[i] ] + vp8_block2left[i]; + + *a = *l = 0; + } + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + a = A[Y2CONTEXT] + vp8_block2above[24]; + l = L[Y2CONTEXT] + vp8_block2left[24]; + *a = *l = 0; + } + + +} + +#define ONYXBLOCK2CONTEXT_OFFSET 0 +#define ONYXBLOCK2LEFT_OFFSET 25 +#define ONYXBLOCK2ABOVE_OFFSET 50 + +DECLARE_ALIGNED(16, const static unsigned char, norm[128]) = +{ + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +void init_detokenizer(VP8D_COMP *dx) +{ + const VP8_COMMON *const oc = & dx->common; + MACROBLOCKD *x = & dx->mb; + + dx->detoken.norm_ptr = (unsigned char *)norm; + dx->detoken.vp8_coef_tree_ptr = (vp8_tree_index *)vp8_coef_tree; + dx->detoken.ptr_onyxblock2context_leftabove = (UINT8 *)vp8_block2context_leftabove; + dx->detoken.ptr_onyx_coef_bands_x = vp8_coef_bands_x; + dx->detoken.scan = (int *)vp8_default_zig_zag1d; + dx->detoken.teb_base_ptr = (TOKENEXTRABITS *)vp8d_token_extra_bits2; + + dx->detoken.qcoeff_start_ptr = &x->qcoeff[0]; + + + dx->detoken.coef_probs[0] = (unsigned char *)(oc->fc.coef_probs [0] [ 0 ] [0]); + dx->detoken.coef_probs[1] = (unsigned char *)(oc->fc.coef_probs [1] [ 0 ] [0]); + dx->detoken.coef_probs[2] = (unsigned char *)(oc->fc.coef_probs [2] [ 0 ] [0]); + dx->detoken.coef_probs[3] = (unsigned char *)(oc->fc.coef_probs [3] [ 0 ] [0]); + +} + +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + + +//shift = norm[range]; \ +// shift = norm_ptr[range]; \ + +#define NORMALIZE \ + /*if(range < 0x80)*/ \ + { \ + shift = detoken->norm_ptr[range]; \ + range <<= shift; \ + value <<= shift; \ + count -= shift; \ + if(count <= 0) \ + { \ + count += BR_COUNT ; \ + value |= (*bufptr) << (BR_COUNT-count); \ + bufptr++; \ + } \ + } +#if 1 +#define DECODE_AND_APPLYSIGN(value_to_sign) \ + split = (range + 1) >> 1; \ + if ( (value >> 24) < split ) \ + { \ + range = split; \ + v= value_to_sign; \ + } \ + else \ + { \ + range = range-split; \ + value = value-(split<<24); \ + v = -value_to_sign; \ + } \ + range +=range; \ + value +=value; \ + if (!--count) \ + { \ + count = BR_COUNT; \ + value |= *bufptr; \ + bufptr++; \ + } + +#define DECODE_AND_BRANCH_IF_ZERO(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) )>> 8); \ + if ( (value >> 24) < split ) \ + { \ + range = split; \ + NORMALIZE \ + goto branch; \ + } \ + value -= (split<<24); \ + range = range - split; \ + NORMALIZE \ + } + +#define DECODE_AND_LOOP_IF_ZERO(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) ) >> 8); \ + if ( (value >> 24) < split ) \ + { \ + range = split; \ + NORMALIZE \ + Prob = coef_probs; \ + ++c; \ + Prob += vp8_coef_bands_x[c]; \ + goto branch; \ + } \ + value -= (split<<24); \ + range = range - split; \ + NORMALIZE \ + } + +#define DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val) \ + DECODE_AND_APPLYSIGN(val) \ + Prob = coef_probs + (ENTROPY_NODES*2); \ + if(c < 15){\ + qcoeff_ptr [ scan[c] ] = (INT16) v; \ + ++c; \ + goto DO_WHILE; }\ + qcoeff_ptr [ scan[15] ] = (INT16) v; \ + goto BLOCK_FINISHED; + + +#define DECODE_EXTRABIT_AND_ADJUST_VAL(t,bits_count)\ + split = 1 + (((range-1) * vp8d_token_extra_bits2[t].Probs[bits_count]) >> 8); \ + if(value >= (split<<24))\ + {\ + range = range-split;\ + value = value-(split<<24);\ + val += ((UINT16)1<<bits_count);\ + }\ + else\ + {\ + range = split;\ + }\ + NORMALIZE +#endif + +#if 0 +int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) +{ + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + const VP8_COMMON *const oc = & dx->common; + + BOOL_DECODER *bc = x->current_bc; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + int eobtotal = 0; + + register int count; + + BOOL_DATA *bufptr; + register unsigned int range; + register unsigned int value; + const int *scan; + register unsigned int shift; + UINT32 split; + INT16 *qcoeff_ptr; + + UINT8 *coef_probs; + int type; + int stop; + INT16 val, bits_count; + INT16 c; + INT16 t; + INT16 v; + vp8_prob *Prob; + + //int *scan; + type = 3; + i = 0; + stop = 16; + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + i = 24; + stop = 24; + type = 1; + qcoeff_ptr = &x->qcoeff[24*16]; + scan = vp8_default_zig_zag1d; + eobtotal -= 16; + } + else + { + scan = vp8_default_zig_zag1d; + qcoeff_ptr = &x->qcoeff[0]; + } + + count = bc->count; + range = bc->range; + value = bc->value; + bufptr = &bc->buffer[bc->pos]; + + + coef_probs = (unsigned char *)(oc->fc.coef_probs [type] [ 0 ] [0]); + +BLOCK_LOOP: + a = A[ vp8_block2context[i] ] + vp8_block2above[i]; + l = L[ vp8_block2context[i] ] + vp8_block2left[i]; + c = (INT16)(!type); + + VP8_COMBINEENTROPYCONTEXTS(t, *a, *l); + Prob = coef_probs; + Prob += t * ENTROPY_NODES; + +DO_WHILE: + Prob += vp8_coef_bands_x[c]; + DECODE_AND_BRANCH_IF_ZERO(Prob[EOB_CONTEXT_NODE], BLOCK_FINISHED); + +CHECK_0_: + DECODE_AND_LOOP_IF_ZERO(Prob[ZERO_CONTEXT_NODE], CHECK_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[ONE_CONTEXT_NODE], ONE_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[LOW_VAL_CONTEXT_NODE], LOW_VAL_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[HIGH_LOW_CONTEXT_NODE], HIGH_LOW_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREEFOUR_CONTEXT_NODE], CAT_THREEFOUR_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_FIVE_CONTEXT_NODE], CAT_FIVE_CONTEXT_NODE_0_); + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY6].min_val; + bits_count = vp8d_token_extra_bits2[DCT_VAL_CATEGORY6].Length; + + do + { + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY6, bits_count); + bits_count -- ; + } + while (bits_count >= 0); + + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_FIVE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY5].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 4); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_THREEFOUR_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREE_CONTEXT_NODE], CAT_THREE_CONTEXT_NODE_0_); + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY4].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_THREE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY3].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +HIGH_LOW_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_ONE_CONTEXT_NODE], CAT_ONE_CONTEXT_NODE_0_); + + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY2].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY2, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY2, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_ONE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY1].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY1, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +LOW_VAL_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[TWO_CONTEXT_NODE], TWO_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[THREE_CONTEXT_NODE], THREE_CONTEXT_NODE_0_); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(4); + +THREE_CONTEXT_NODE_0_: + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(3); + +TWO_CONTEXT_NODE_0_: + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(2); + +ONE_CONTEXT_NODE_0_: + DECODE_AND_APPLYSIGN(1); + Prob = coef_probs + ENTROPY_NODES; + + if (c < 15) + { + qcoeff_ptr [ scan[c] ] = (INT16) v; + ++c; + goto DO_WHILE; + } + + qcoeff_ptr [ scan[15] ] = (INT16) v; +BLOCK_FINISHED: + t = ((x->Block[i].eob = c) != !type); // any nonzero data? + eobtotal += x->Block[i].eob; + *a = *l = t; + qcoeff_ptr += 16; + + i++; + + if (i < stop) + goto BLOCK_LOOP; + + if (i == 25) + { + scan = vp8_default_zig_zag1d;//x->scan_order1d; + type = 0; + i = 0; + stop = 16; + coef_probs = (unsigned char *)(oc->fc.coef_probs [type] [ 0 ] [0]); + qcoeff_ptr = &x->qcoeff[0]; + goto BLOCK_LOOP; + } + + if (i == 16) + { + type = 2; + coef_probs = (unsigned char *)(oc->fc.coef_probs [type] [ 0 ] [0]); + stop = 24; + goto BLOCK_LOOP; + } + + bc->count = count; + bc->value = value; + bc->range = range; + bc->pos = bufptr - bc->buffer; + return eobtotal; + +} +//#endif +#else +/* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +#if 0 +//uses relative offsets + +const vp8_tree_index vp8_coef_tree_x[ 22] = /* corresponding _CONTEXT_NODEs */ +{ + -DCT_EOB_TOKEN, 1, /* 0 = EOB */ + -ZERO_TOKEN, 1, /* 1 = ZERO */ + -ONE_TOKEN, 1, /* 2 = ONE */ + 2, 5, /* 3 = LOW_VAL */ + -TWO_TOKEN, 1, /* 4 = TWO */ + -THREE_TOKEN, -FOUR_TOKEN, /* 5 = THREE */ + 2, 3, /* 6 = HIGH_LOW */ + -DCT_VAL_CATEGORY1, -DCT_VAL_CATEGORY2, /* 7 = CAT_ONE */ + 2, 3, /* 8 = CAT_THREEFOUR */ + -DCT_VAL_CATEGORY3, -DCT_VAL_CATEGORY4, /* 9 = CAT_THREE */ + -DCT_VAL_CATEGORY5, -DCT_VAL_CATEGORY6 /* 10 = CAT_FIVE */ +}; +#endif + +#define _SCALEDOWN 8 //16 //8 + +int vp8_decode_mb_tokens_v5(DETOK *detoken, int type); + +int vp8_decode_mb_tokens_v5_c(DETOK *detoken, int type) +{ + BOOL_DECODER *bc = detoken->current_bc; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + register int count; + + BOOL_DATA *bufptr; + register unsigned int range; + register unsigned int value; + register unsigned int shift; + UINT32 split; + INT16 *qcoeff_ptr; + + UINT8 *coef_probs; +// int type; + int stop; + INT16 c; + INT16 t; + INT16 v; + vp8_prob *Prob; + + + +// type = 3; + i = 0; + stop = 16; + qcoeff_ptr = detoken->qcoeff_start_ptr; + +// if( detoken->mode != B_PRED && detoken->mode != SPLITMV) + if (type == 1) + { + i += 24; + stop += 8; //24; +// type = 1; + qcoeff_ptr += 24 * 16; +// eobtotal-=16; + } + + count = bc->count; + range = bc->range; + value = bc->value; + bufptr = &bc->buffer[bc->pos]; + + + coef_probs = detoken->coef_probs[type]; //(unsigned char *)( oc->fc.coef_probs [type] [ 0 ] [0]); + +BLOCK_LOOP: + a = detoken->A[ detoken->ptr_onyxblock2context_leftabove[i] ]; + l = detoken->L[ detoken->ptr_onyxblock2context_leftabove[i] ]; + c = !type; + a += detoken->ptr_onyxblock2context_leftabove[i + ONYXBLOCK2ABOVE_OFFSET]; + l += detoken->ptr_onyxblock2context_leftabove[i + ONYXBLOCK2LEFT_OFFSET]; + + //#define ONYX_COMBINEENTROPYCONTEXTS( Dest, A, B) \ + //Dest = ((A)!=0) + ((B)!=0); + + VP8_COMBINEENTROPYCONTEXTS(t, *a, *l); + + Prob = coef_probs; + Prob += t * ENTROPY_NODES; + t = 0; + + do + { + + { +// onyx_tree_index * onyx_coef_tree_ptr = onyx_coef_tree_x; + + Prob += detoken->ptr_onyx_coef_bands_x[c]; + + GET_TOKEN_START: + + do + { + split = 1 + (((range - 1) * (Prob[t>>1])) >> 8); + + if (value >> 24 >= split) + { + range = range - split; + value = value - (split << 24); + t += 1; + + //used to eliminate else branch + split = range; + } + + range = split; + + t = detoken->vp8_coef_tree_ptr[ t ]; + + NORMALIZE + + } + while (t > 0) ; + } + GET_TOKEN_STOP: + + if (t == -DCT_EOB_TOKEN) + { + break; + } + + v = -t; + + if (v > FOUR_TOKEN) + { + INT16 bits_count; + TOKENEXTRABITS *teb_ptr; + +// teb_ptr = &onyxd_token_extra_bits2[t]; +// teb_ptr = &onyxd_token_extra_bits2[v]; + teb_ptr = &detoken->teb_base_ptr[v]; + + + v = teb_ptr->min_val; + bits_count = teb_ptr->Length; + + do + { + split = 1 + (((range - 1) * teb_ptr->Probs[bits_count]) >> _SCALEDOWN); + + if ((value >> 24) >= split) + { + range = range - split; + value = value - (split << 24); + v += ((UINT16)1 << bits_count); + + //used to eliminate else branch + split = range; + } + + range = split; + + NORMALIZE + + bits_count -- ; + } + while (bits_count >= 0); + } + + Prob = coef_probs; + + if (t) + { + split = 1 + (((range - 1) * vp8_prob_half) >> 8); + + if ((value >> 24) >= split) + { + range = range - split; + value = value - (split << 24); + v = (v ^ -1) + 1; /* negate w/out conditionals */ + + //used to eliminate else branch + split = range; + } + + range = split; + + NORMALIZE + Prob += ENTROPY_NODES; + + if (t < -ONE_TOKEN) + Prob += ENTROPY_NODES; + + t = -2; + } + + //if t is zero, we will skip the eob table check + t += 2; + qcoeff_ptr [detoken->scan [c] ] = (INT16) v; + + } + while (++c < 16); + + if (t != -DCT_EOB_TOKEN) + { + --c; + } + + t = ((detoken->eob[i] = c) != !type); // any nonzero data? +// eobtotal += detoken->eob[i]; + *a = *l = t; + qcoeff_ptr += 16; + + i++; + + if (i < stop) + goto BLOCK_LOOP; + + if (i == 25) + { + type = 0; + i = 0; + stop = 16; +// coef_probs = (unsigned char *)(oc->fc.coef_probs [type] [ 0 ] [0]); + coef_probs = detoken->coef_probs[type]; //(unsigned char *)( oc->fc.coef_probs [type] [ 0 ] [0]); + qcoeff_ptr = detoken->qcoeff_start_ptr; + goto BLOCK_LOOP; + } + + if (i == 16) + { + type = 2; +// coef_probs =(unsigned char *)( oc->fc.coef_probs [type] [ 0 ] [0]); + coef_probs = detoken->coef_probs[type]; //(unsigned char *)( oc->fc.coef_probs [type] [ 0 ] [0]); + stop = 24; + goto BLOCK_LOOP; + } + + bc->count = count; + bc->value = value; + bc->range = range; + bc->pos = bufptr - bc->buffer; + return 0; +} +//#if 0 +int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) +{ +// const ONYX_COMMON * const oc = & dx->common; + int eobtotal = 0; + int i, type; + /* + dx->detoken.norm_ptr = norm; + dx->detoken.onyx_coef_tree_ptr = onyx_coef_tree; + dx->detoken.ptr_onyxblock2context_leftabove = ONYXBLOCK2CONTEXT_LEFTABOVE; + dx->detoken.ptr_onyx_coef_bands_x = onyx_coef_bands_x; + dx->detoken.scan = default_zig_zag1d; + dx->detoken.teb_base_ptr = onyxd_token_extra_bits2; + + dx->detoken.qcoeff_start_ptr = &x->qcoeff[0]; + + dx->detoken.A = x->above_context; + dx->detoken.L = x->left_context; + + dx->detoken.coef_probs[0] = (unsigned char *)( oc->fc.coef_probs [0] [ 0 ] [0]); + dx->detoken.coef_probs[1] = (unsigned char *)( oc->fc.coef_probs [1] [ 0 ] [0]); + dx->detoken.coef_probs[2] = (unsigned char *)( oc->fc.coef_probs [2] [ 0 ] [0]); + dx->detoken.coef_probs[3] = (unsigned char *)( oc->fc.coef_probs [3] [ 0 ] [0]); + */ + + dx->detoken.current_bc = x->current_bc; + dx->detoken.A = x->above_context; + dx->detoken.L = x->left_context; + + type = 3; + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + type = 1; + eobtotal -= 16; + } + + vp8_decode_mb_tokens_v5(&dx->detoken, type); + + for (i = 0; i < 25; i++) + { + x->Block[i].eob = dx->detoken.eob[i]; + eobtotal += dx->detoken.eob[i]; + } + + return eobtotal; +} +#endif
diff --git a/vp8/decoder/arm/detokenizearm_v6.asm b/vp8/decoder/arm/detokenizearm_v6.asm new file mode 100644 index 0000000..4d87ee5 --- /dev/null +++ b/vp8/decoder/arm/detokenizearm_v6.asm
@@ -0,0 +1,364 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_decode_mb_tokens_v5| + + AREA |.text|, CODE, READONLY ; name this block of code + + INCLUDE vpx_asm_offsets.asm + +l_qcoeff EQU 0 +l_i EQU 4 +l_type EQU 8 +l_stop EQU 12 +l_c EQU 16 +l_l_ptr EQU 20 +l_a_ptr EQU 24 +l_bc EQU 28 +l_coef_ptr EQU 32 +l_stacksize EQU 64 + + +;; constant offsets -- these should be created at build time +c_onyxblock2left_offset EQU 25 +c_onyxblock2above_offset EQU 50 +c_entropy_nodes EQU 11 +c_dct_eob_token EQU 11 + +|vp8_decode_mb_tokens_v5| PROC + stmdb sp!, {r4 - r11, lr} + sub sp, sp, #l_stacksize + mov r7, r1 + mov r9, r0 ;DETOK *detoken + + ldr r1, [r9, #detok_current_bc] + ldr r0, [r9, #detok_qcoeff_start_ptr] + mov r11, #0 + mov r3, #0x10 + + cmp r7, #1 + addeq r11, r11, #24 + addeq r3, r3, #8 + addeq r0, r0, #3, 24 + + str r0, [sp, #l_qcoeff] + str r11, [sp, #l_i] + str r7, [sp, #l_type] + str r3, [sp, #l_stop] + str r1, [sp, #l_bc] + + add lr, r9, r7, lsl #2 + + ldr r2, [r1, #bool_decoder_buffer] + ldr r3, [r1, #bool_decoder_pos] + + ldr r10, [lr, #detok_coef_probs] + ldr r5, [r1, #bool_decoder_count] + ldr r6, [r1, #bool_decoder_range] + ldr r4, [r1, #bool_decoder_value] + add r8, r2, r3 + + str r10, [sp, #l_coef_ptr] + + + ;align 4 +BLOCK_LOOP + ldr r3, [r9, #detok_ptr_onyxblock2context_leftabove] + ldr r2, [r9, #DETOK_A] + ldr r1, [r9, #DETOK_L] + ldrb r12, [r3, +r11] ; detoken->ptr_onyxblock2context_leftabove[i] + + cmp r7, #0 ; check type + moveq r7, #1 + movne r7, #0 + + ldr r0, [r2, +r12, lsl #2] ; a + add r1, r1, r12, lsl #4 + add r3, r3, r11 + + ldrb r2, [r3, #c_onyxblock2above_offset] + ldrb r3, [r3, #c_onyxblock2left_offset] + mov lr, #c_entropy_nodes +;; ;++ + + ldr r2, [r0, +r2, lsl #2]! + add r3, r1, r3, lsl #2 + str r3, [sp, #l_l_ptr] + ldr r3, [r3] + + cmp r2, #0 + movne r2, #1 + cmp r3, #0 + addne r2, r2, #1 + + str r0, [sp, #l_a_ptr] + smlabb r0, r2, lr, r10 + mov r1, #0 ; t = 0 + str r7, [sp, #l_c] + + ;align 4 +COEFF_LOOP + ldr r3, [r9, #detok_ptr_onyx_coef_bands_x] + ldr lr, [r9, #detok_onyx_coef_tree_ptr] + +;;the following two lines are used if onyx_coef_bands_x is UINT16 +;; add r3, r3, r7, lsl #1 +;; ldrh r3, [r3] + +;;the following line is used if onyx_coef_bands_x is UINT8 + ldrb r3, [r7, +r3] + + +;; ;++ +;; pld [r8] + ;++ + add r0, r0, r3 + + ;align 4 +get_token_loop + ldrb r2, [r0, +r1, asr #1] + mov r3, r6, lsl #8 + sub r3, r3, #256 ;split = 1 + (((range-1) * probability) >> 8) + mov r10, #1 + + smlawb r2, r3, r2, r10 + ldrb r12, [r8] ;load cx data byte in stall slot + ;++ + + subs r3, r4, r2, lsl #24 ;x = value-(split<<24) + addhs r1, r1, #1 ;t += 1 + movhs r4, r3 ;update value + subhs r2, r6, r2 ;range = range - split + movlo r6, r2 + +;;; ldrsbhs r1, [r1, +lr] + ldrsb r1, [r1, +lr] + + +;; use branch for short pipelines ??? +;; cmp r2, #0x80 +;; bcs |$LN22@decode_mb_to| + + clz r3, r2 + sub r3, r3, #24 + subs r5, r5, r3 + mov r6, r2, lsl r3 + mov r4, r4, lsl r3 + +;; use branch for short pipelines ??? +;; bgt |$LN22@decode_mb_to| + + addle r5, r5, #8 + rsble r3, r5, #8 + addle r8, r8, #1 + orrle r4, r4, r12, lsl r3 + +;;|$LN22@decode_mb_to| + + cmp r1, #0 + bgt get_token_loop + + cmn r1, #c_dct_eob_token ;if(t == -DCT_EOB_TOKEN) + beq END_OF_BLOCK + + rsb lr, r1, #0 ;v = -t; + + cmp lr, #4 ;if(v > FOUR_TOKEN) + ble SKIP_EXTRABITS + + ldr r3, [r9, #detok_teb_base_ptr] + mov r11, #1 + add r7, r3, lr, lsl #4 + + ldrsh lr, [r7, #tokenextrabits_min_val];v = teb_ptr->min_val + ldrsh r0, [r7, #tokenextrabits_length];bits_count = teb_ptr->Length + +extrabits_loop + add r3, r0, r7 + + ldrb r2, [r3, #4] + mov r3, r6, lsl #8 + sub r3, r3, #256 ;split = 1 + (((range-1) * probability) >> 8) + mov r10, #1 + + smlawb r2, r3, r2, r10 + ldrb r12, [r8] + ;++ + + subs r10, r4, r2, lsl #24 ;x = value-(split<<24) + movhs r4, r10 ;update value + subhs r2, r6, r2 ;range = range - split + addhs lr, lr, r11, lsl r0 ;v += ((UINT16)1<<bits_count) + movlo r6, r2 ;range = split + + +;; use branch for short pipelines ??? +;; cmp r2, #0x80 +;; bcs |$LN10@decode_mb_to| + + clz r3, r2 + sub r3, r3, #24 + subs r5, r5, r3 + mov r6, r2, lsl r3 ;range + mov r4, r4, lsl r3 ;value + + addle r5, r5, #8 + addle r8, r8, #1 + rsble r3, r5, #8 + orrle r4, r4, r12, lsl r3 + +;;|$LN10@decode_mb_to| + subs r0, r0, #1 + bpl extrabits_loop + + +SKIP_EXTRABITS + ldr r11, [sp, #l_qcoeff] + ldr r0, [sp, #l_coef_ptr] + + cmp r1, #0 ;check for nonzero token + beq SKIP_EOB_CHECK ;if t is zero, we will skip the eob table chec + + sub r3, r6, #1 ;range - 1 + ;++ + mov r3, r3, lsl #7 ; *= onyx_prob_half (128) + ;++ + mov r3, r3, lsr #8 + add r2, r3, #1 ;split + + subs r3, r4, r2, lsl #24 ;x = value-(split<<24) + movhs r4, r3 ;update value + subhs r2, r6, r2 ;range = range - split + mvnhs r3, lr + addhs lr, r3, #1 ;v = (v ^ -1) + 1 + movlo r6, r2 ;range = split + +;; use branch for short pipelines ??? +;; cmp r2, #0x80 +;; bcs |$LN6@decode_mb_to| + + clz r3, r2 + sub r3, r3, #24 + subs r5, r5, r3 + mov r6, r2, lsl r3 + mov r4, r4, lsl r3 + ldrleb r2, [r8], #1 + addle r5, r5, #8 + rsble r3, r5, #8 + orrle r4, r4, r2, lsl r3 + +;;|$LN6@decode_mb_to| + add r0, r0, #0xB + + cmn r1, #1 + + addlt r0, r0, #0xB + + mvn r1, #1 + +SKIP_EOB_CHECK + ldr r7, [sp, #l_c] + ldr r3, [r9, #detok_scan] + add r1, r1, #2 + cmp r7, #(0x10 - 1) ;assume one less for now.... increment below + + ldr r3, [r3, +r7, lsl #2] + add r7, r7, #1 + add r3, r11, r3, lsl #1 + + str r7, [sp, #l_c] + strh lr, [r3] + + blt COEFF_LOOP + + sub r7, r7, #1 ;if(t != -DCT_EOB_TOKEN) --c + +END_OF_BLOCK + ldr r3, [sp, #l_type] + ldr r10, [sp, #l_coef_ptr] + ldr r0, [sp, #l_qcoeff] + ldr r11, [sp, #l_i] + ldr r12, [sp, #l_stop] + + cmp r3, #0 + moveq r1, #1 + movne r1, #0 + add r3, r11, r9 + + cmp r7, r1 + strb r7, [r3, #detok_eob] + + ldr r7, [sp, #l_l_ptr] + ldr r2, [sp, #l_a_ptr] + movne r3, #1 + moveq r3, #0 + + add r0, r0, #0x20 + add r11, r11, #1 + str r3, [r7] + str r3, [r2] + str r0, [sp, #l_qcoeff] + str r11, [sp, #l_i] + + cmp r11, r12 ;i >= stop ? + ldr r7, [sp, #l_type] + mov lr, #0xB + + blt BLOCK_LOOP + + cmp r11, #0x19 + bne ln2_decode_mb_to + + ldr r12, [r9, #detok_qcoeff_start_ptr] + ldr r10, [r9, #detok_coef_probs] + mov r7, #0 + mov r3, #0x10 + str r12, [sp, #l_qcoeff] + str r7, [sp, #l_i] + str r7, [sp, #l_type] + str r3, [sp, #l_stop] + + str r10, [sp, #l_coef_ptr] + + b BLOCK_LOOP + +ln2_decode_mb_to + cmp r11, #0x10 + bne ln1_decode_mb_to + + ldr r10, [r9, #0x30] + + mov r7, #2 + mov r3, #0x18 + + str r7, [sp, #l_type] + str r3, [sp, #l_stop] + + str r10, [sp, #l_coef_ptr] + b BLOCK_LOOP + +ln1_decode_mb_to + ldr r2, [sp, #l_bc] + mov r0, #0 + nop + + ldr r3, [r2, #bool_decoder_buffer] + str r5, [r2, #bool_decoder_count] + str r4, [r2, #bool_decoder_value] + sub r3, r8, r3 + str r3, [r2, #bool_decoder_pos] + str r6, [r2, #bool_decoder_range] + + add sp, sp, #l_stacksize + ldmia sp!, {r4 - r11, pc} + + ENDP ; |vp8_decode_mb_tokens_v5| + + END
diff --git a/vp8/decoder/arm/dsystemdependent.c b/vp8/decoder/arm/dsystemdependent.c new file mode 100644 index 0000000..455c83a --- /dev/null +++ b/vp8/decoder/arm/dsystemdependent.c
@@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "blockd.h" +#include "pragmas.h" +#include "postproc.h" +#include "dboolhuff.h" +#include "dequantize.h" +#include "onyxd_int.h" + +void vp8_dmachine_specific_config(VP8D_COMP *pbi) +{ +#if CONFIG_RUNTIME_CPU_DETECT + pbi->mb.rtcd = &pbi->common.rtcd; +#if HAVE_ARMV7 + pbi->dequant.block = vp8_dequantize_b_neon; + pbi->dequant.idct = vp8_dequant_idct_neon; + pbi->dequant.idct_dc = vp8_dequant_dc_idct_neon; + pbi->dboolhuff.start = vp8dx_start_decode_c; + pbi->dboolhuff.stop = vp8dx_stop_decode_c; + pbi->dboolhuff.fill = vp8dx_bool_decoder_fill_c; + pbi->dboolhuff.debool = vp8dx_decode_bool_c; + pbi->dboolhuff.devalue = vp8dx_decode_value_c; + +#elif HAVE_ARMV6 + pbi->dequant.block = vp8_dequantize_b_v6; + pbi->dequant.idct = vp8_dequant_idct_v6; + pbi->dequant.idct_dc = vp8_dequant_dc_idct_v6; + pbi->dboolhuff.start = vp8dx_start_decode_c; + pbi->dboolhuff.stop = vp8dx_stop_decode_c; + pbi->dboolhuff.fill = vp8dx_bool_decoder_fill_c; + pbi->dboolhuff.debool = vp8dx_decode_bool_c; + pbi->dboolhuff.devalue = vp8dx_decode_value_c; +#endif +#endif +}
diff --git a/vp8/decoder/arm/neon/dboolhuff_neon.asm b/vp8/decoder/arm/neon/dboolhuff_neon.asm new file mode 100644 index 0000000..7ec62a3 --- /dev/null +++ b/vp8/decoder/arm/neon/dboolhuff_neon.asm
@@ -0,0 +1,159 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_decode_value_neon| + EXPORT |vp8dx_start_decode_neon| + EXPORT |vp8dx_stop_decode_neon| + EXPORT |vp8dx_decode_bool_neon| + + ARM + REQUIRE8 + PRESERVE8 + + INCLUDE vpx_asm_offsets.asm + + AREA |.text|, CODE, READONLY ; name this block of code + +; int z = 0; +; int bit; +; for ( bit=bits-1; bit>=0; bit-- ) +; { +; z |= (vp8dx_decode_bool(br, 0x80)<<bit); +; } +; return z; + +;int vp8_decode_value_neon ( BOOL_DECODER *br, int bits ) +|vp8_decode_value_neon| PROC + stmdb sp!, {r4 - r6, lr} + mov r4, r0 + mov r5, r1 + mov r6, #0 + + subs r5, r5, #1 + bmi decode_value_exit + +decode_value_loop + mov r1, #0x80 + mov r0, r4 + bl vp8dx_decode_bool_neon_internal ; needed for conversion to s file + orr r6, r6, r0, lsl r5 + subs r5, r5, #1 + bpl decode_value_loop + +decode_value_exit + mov r0, r6 + ldmia sp!, {r4 - r6, pc} + ENDP ; |vp8_decode_value_neon| + + +;void vp8dx_start_decode_neon ( BOOL_DECODER *br, unsigned char *source ) +|vp8dx_start_decode_neon| PROC + stmdb sp!, {r4 - r5, lr} + mov r2, #0 + mov r3, #255 + + str r2, [r0, #bool_decoder_lowvalue] + str r3, [r0, #bool_decoder_range] + str r1, [r0, #bool_decoder_buffer] + + mov r3, #8 + mov r2, #4 + str r3, [r0, #bool_decoder_count] + str r2, [r0, #bool_decoder_pos] + + ldrb r2, [r1, #3] + ldrb r3, [r1, #2] + ldrb r4, [r1, #1] + ldrb r5, [r1] + + orr r1, r2, r3, lsl #8 + orr r1, r1, r4, lsl #16 + orr r1, r1, r5, lsl #24 + + str r1, [r0, #bool_decoder_value] + + ldmia sp!, {r4 - r5, pc} + ENDP ; |vp8dx_start_decode_neon| + + +;void vp8dx_stop_decode_neon ( BOOL_DECODER *bc ); +|vp8dx_stop_decode_neon| PROC + mov pc, lr + ENDP ; |vp8dx_stop_decode_neon| + + +; bigsplit RN r1 +; buffer_v RN r1 +; count_v RN r4 +; range_v RN r2 +; value_v RN r3 +; pos_v RN r5 +; split RN r6 +; bit RN lr +;int vp8dx_decode_bool_neon ( BOOL_DECODER *br, int probability ) +|vp8dx_decode_bool_neon| PROC +vp8dx_decode_bool_neon_internal +;LDRD and STRD doubleword data transfers must be eight-byte aligned. Use ALIGN 8 +;before memory allocation + stmdb sp!, {r4 - r5, lr} + + ldr r2, [r0, #bool_decoder_range] ;load range (r2), value(r3) + ldr r3, [r0, #bool_decoder_value] + ;ldrd r2, r3, [r0, #bool_decoder_range] ;ldrd costs 2 cycles + ; + + mov r4, r2, lsl #8 + sub r4, r4, #256 + mov r12, #1 + + smlawb r4, r4, r1, r12 ;split = 1 + (((range-1) * probability) >> 8) + + mov lr, r0 + mov r0, #0 ;bit = 0 + ; + subs r5, r3, r4, lsl #24 + + subhs r2, r2, r4 ;range = br->range-split + movlo r2, r4 ;range = split + movhs r0, #1 ;bit = 1 + movhs r3, r5 ;value = value-bigsplit + + cmp r2, #0x80 + blt range_less_0x80 + strd r2, r3, [lr, #bool_decoder_range] ;store result + + ldmia sp!, {r4 - r5, pc} + +range_less_0x80 + + ldrd r4, r5, [lr, #bool_decoder_count] ;load count, pos, buffer + ldr r1, [lr, #bool_decoder_buffer] + + clz r12, r2 + add r1, r1, r5 + + sub r12, r12, #24 + subs r4, r4, r12 ;count -= shift + mov r2, r2, lsl r12 ;range <<= shift + mov r3, r3, lsl r12 ;value <<= shift + addle r4, r4, #8 ;count += 8 + ldrleb r12, [r1], #1 ;br->buffer[br->pos] + + rsble r1, r4, #8 ;-count + addle r5, r5, #1 ;br->pos++ + orrle r3, r3, r12, lsl r1 ;value |= (br->buffer[br->pos]) << (-count) + + strd r2, r3, [lr, #bool_decoder_range] ;store result + strd r4, r5, [lr, #bool_decoder_count] + + ldmia sp!, {r4 - r5, pc} + ENDP ; |vp8dx_decode_bool_neon| + + END
diff --git a/vp8/decoder/arm/neon/dequantdcidct_neon.asm b/vp8/decoder/arm/neon/dequantdcidct_neon.asm new file mode 100644 index 0000000..3392f2c --- /dev/null +++ b/vp8/decoder/arm/neon/dequantdcidct_neon.asm
@@ -0,0 +1,133 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequant_dc_idct_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_dequant_dc_idct_c(short *input, short *dq, short *output, int pitch, int Dc); +; r0 short *input, +; r1 short *dq, +; r2 short *output, +; r3 int pitch, +; (stack) int Dc +|vp8_dequant_dc_idct_neon| PROC + vld1.16 {q3, q4}, [r0] + vld1.16 {q5, q6}, [r1] + + ldr r1, [sp] ;load Dc from stack + + ldr r12, _dcidct_coeff_ + + vmul.i16 q1, q3, q5 ;input for short_idct4x4llm_neon + vmul.i16 q2, q4, q6 + + vmov.16 d2[0], r1 + +;|short_idct4x4llm_neon| PROC + vld1.16 {d0}, [r12] + vswp d3, d4 ;q2(vp[4] vp[12]) + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + ;d6 - c1:temp1 + ;d7 - d1:temp2 + ;d8 - d1:temp1 + ;d9 - c1:temp2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + +; memset(input, 0, 32) -- 32bytes + vmov.i16 q14, #0 + + vswp d3, d4 + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vmov q15, q14 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vst1.16 {q14, q15}, [r0] + + vrshr.s16 d2, d2, #3 + vrshr.s16 d3, d3, #3 + vrshr.s16 d4, d4, #3 + vrshr.s16 d5, d5, #3 + + add r1, r2, r3 + add r12, r1, r3 + add r0, r12, r3 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vst1.16 {d2}, [r2] + vst1.16 {d3}, [r1] + vst1.16 {d4}, [r12] + vst1.16 {d5}, [r0] + + bx lr + + ENDP + +;----------------- + AREA dcidct4x4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_dcidct_coeff_ + DCD dcidct_coeff +dcidct_coeff + DCD 0x4e7b4e7b, 0x8a8c8a8c + +;20091, 20091, 35468, 35468 + + END
diff --git a/vp8/decoder/arm/neon/dequantidct_neon.asm b/vp8/decoder/arm/neon/dequantidct_neon.asm new file mode 100644 index 0000000..bba4d5d --- /dev/null +++ b/vp8/decoder/arm/neon/dequantidct_neon.asm
@@ -0,0 +1,128 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequant_idct_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_dequant_idct_c(short *input, short *dq, short *output, int pitch); +; r0 short *input, +; r1 short *dq, +; r2 short *output, +; r3 int pitch, +|vp8_dequant_idct_neon| PROC + vld1.16 {q3, q4}, [r0] + vld1.16 {q5, q6}, [r1] + + ldr r12, _didct_coeff_ + + vmul.i16 q1, q3, q5 ;input for short_idct4x4llm_neon + vmul.i16 q2, q4, q6 + +;|short_idct4x4llm_neon| PROC + vld1.16 {d0}, [r12] + vswp d3, d4 ;q2(vp[4] vp[12]) + + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + ;d6 - c1:temp1 + ;d7 - d1:temp2 + ;d8 - d1:temp1 + ;d9 - c1:temp2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + +; memset(input, 0, 32) -- 32bytes + vmov.i16 q14, #0 + + vswp d3, d4 + vqdmulh.s16 q3, q2, d0[2] + vqdmulh.s16 q4, q2, d0[0] + + vqadd.s16 d12, d2, d3 ;a1 + vqsub.s16 d13, d2, d3 ;b1 + + vmov q15, q14 + + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vqadd.s16 q3, q3, q2 ;modify since sinpi8sqrt2 > 65536/2 (negtive number) + vqadd.s16 q4, q4, q2 + + vqsub.s16 d10, d6, d9 ;c1 + vqadd.s16 d11, d7, d8 ;d1 + + vqadd.s16 d2, d12, d11 + vqadd.s16 d3, d13, d10 + vqsub.s16 d4, d13, d10 + vqsub.s16 d5, d12, d11 + + vst1.16 {q14, q15}, [r0] + + vrshr.s16 d2, d2, #3 + vrshr.s16 d3, d3, #3 + vrshr.s16 d4, d4, #3 + vrshr.s16 d5, d5, #3 + + add r1, r2, r3 + add r12, r1, r3 + add r0, r12, r3 + + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vst1.16 {d2}, [r2] + vst1.16 {d3}, [r1] + vst1.16 {d4}, [r12] + vst1.16 {d5}, [r0] + + bx lr + + ENDP + +;----------------- + AREA didct4x4_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_didct_coeff_ + DCD didct_coeff +didct_coeff + DCD 0x4e7b4e7b, 0x8a8c8a8c + +;20091, 20091, 35468, 35468 + + END
diff --git a/vp8/decoder/arm/neon/dequantizeb_neon.asm b/vp8/decoder/arm/neon/dequantizeb_neon.asm new file mode 100644 index 0000000..1bde946 --- /dev/null +++ b/vp8/decoder/arm/neon/dequantizeb_neon.asm
@@ -0,0 +1,33 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_dequantize_b_loop_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 short *Q, +; r1 short *DQC +; r2 short *DQ +|vp8_dequantize_b_loop_neon| PROC + vld1.16 {q0, q1}, [r0] + vld1.16 {q2, q3}, [r1] + + vmul.i16 q4, q0, q2 + vmul.i16 q5, q1, q3 + + vst1.16 {q4, q5}, [r2] + + bx lr + + ENDP + + END
diff --git a/vp8/decoder/dboolhuff.c b/vp8/decoder/dboolhuff.c new file mode 100644 index 0000000..442054e --- /dev/null +++ b/vp8/decoder/dboolhuff.c
@@ -0,0 +1,174 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "dboolhuff.h" +#include "vpx_ports/mem.h" +#include "vpx_mem/vpx_mem.h" + +DECLARE_ALIGNED(16, const unsigned int, vp8dx_bitreader_norm[256]) = +{ + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +static void copy_in(BOOL_DECODER *br, unsigned int to_write) +{ + if (to_write > br->user_buffer_sz) + to_write = br->user_buffer_sz; + + memcpy(br->write_ptr, br->user_buffer, to_write); + br->user_buffer += to_write; + br->user_buffer_sz -= to_write; + br->write_ptr = br_ptr_advance(br->write_ptr, to_write); +} + +int vp8dx_start_decode_c(BOOL_DECODER *br, const unsigned char *source, + unsigned int source_sz) +{ + br->lowvalue = 0; + br->range = 255; + br->count = 0; + br->user_buffer = source; + br->user_buffer_sz = source_sz; + + if (source_sz && !source) + return 1; + + /* Allocate the ring buffer backing store with alignment equal to the + * buffer size*2 so that a single pointer can be used for wrapping rather + * than a pointer+offset. + */ + br->decode_buffer = vpx_memalign(VP8_BOOL_DECODER_SZ * 2, + VP8_BOOL_DECODER_SZ); + + if (!br->decode_buffer) + return 1; + + /* Populate the buffer */ + br->read_ptr = br->decode_buffer; + br->write_ptr = br->decode_buffer; + copy_in(br, VP8_BOOL_DECODER_SZ); + + /* Read the first byte */ + br->value = (*br->read_ptr++) << 8; + return 0; +} + + +void vp8dx_bool_decoder_fill_c(BOOL_DECODER *br) +{ + int left, right; + + /* Find available room in the buffer */ + left = 0; + right = br->read_ptr - br->write_ptr; + + if (right < 0) + { + /* Read pointer is behind the write pointer. We can write from the + * write pointer to the end of the buffer. + */ + right = VP8_BOOL_DECODER_SZ - (br->write_ptr - br->decode_buffer); + left = br->read_ptr - br->decode_buffer; + } + + if (right + left < 128) + return; + + if (right) + copy_in(br, right); + + if (left) + { + br->write_ptr = br->decode_buffer; + copy_in(br, left); + } + +} + + +void vp8dx_stop_decode_c(BOOL_DECODER *bc) +{ + vpx_free(bc->decode_buffer); + bc->decode_buffer = 0; +} + +#if 0 +/* + * Until optimized versions of these functions are available, we + * keep the implementation in the header to allow inlining. + * + * The RTCD-style invocations are still in place so this can + * be switched by just uncommenting these functions here and + * the DBOOLHUFF_INVOKE calls in the header. + */ +int vp8dx_decode_bool_c(BOOL_DECODER *br, int probability) +{ + unsigned int bit=0; + unsigned int split; + unsigned int bigsplit; + register unsigned int range = br->range; + register unsigned int value = br->value; + + split = 1 + (((range-1) * probability) >> 8); + bigsplit = (split<<8); + + range = split; + if(value >= bigsplit) + { + range = br->range-split; + value = value-bigsplit; + bit = 1; + } + + /*if(range>=0x80) + { + br->value = value; + br->range = range; + return bit; + }*/ + + { + int count = br->count; + register unsigned int shift = vp8dx_bitreader_norm[range]; + range <<= shift; + value <<= shift; + count -= shift; + if(count <= 0) + { + value |= (*br->read_ptr) << (-count); + br->read_ptr = br_ptr_advance(br->read_ptr, 1); + count += 8 ; + } + br->count = count; + } + br->value = value; + br->range = range; + return bit; +} + +int vp8dx_decode_value_c(BOOL_DECODER *br, int bits) +{ + int z = 0; + int bit; + for ( bit=bits-1; bit>=0; bit-- ) + { + z |= (vp8dx_decode_bool(br, 0x80)<<bit); + } + return z; +} +#endif
diff --git a/vp8/decoder/dboolhuff.h b/vp8/decoder/dboolhuff.h new file mode 100644 index 0000000..f5c9822 --- /dev/null +++ b/vp8/decoder/dboolhuff.h
@@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DBOOLHUFF_H +#define DBOOLHUFF_H +#include "vpx_ports/config.h" +#include "vpx_ports/mem.h" +#include "vpx_ports/vpx_integer.h" + +/* Size of the bool decoder backing storage + * + * This size was chosen to be greater than the worst case encoding of a + * single macroblock. This was calcluated as follows (python): + * + * def max_cost(prob): + * return max(prob_costs[prob], prob_costs[255-prob]) / 256; + * + * tree_nodes_cost = 7 * max_cost(255) + * extra_bits_cost = sum([max_cost(bit) for bit in extra_bits]) + * sign_bit_cost = max_cost(128) + * total_cost = tree_nodes_cost + extra_bits_cost + sign_bit_cost + * + * where the prob_costs table was taken from the C vp8_prob_cost table in + * boolhuff.c and the extra_bits table was taken from the 11 extrabits for + * a category 6 token as defined in vp8d_token_extra_bits2/detokenize.c + * + * This equation produced a maximum of 79 bits per coefficient. Scaling up + * to the macroblock level: + * + * 79 bits/coeff * 16 coeff/block * 25 blocks/macroblock = 31600 b/mb + * + * 4096 bytes = 32768 bits > 31600 + */ +#define VP8_BOOL_DECODER_SZ 4096 +#define VP8_BOOL_DECODER_MASK (VP8_BOOL_DECODER_SZ-1) +#define VP8_BOOL_DECODER_PTR_MASK (~(uintptr_t)(VP8_BOOL_DECODER_SZ)) + +struct vp8_dboolhuff_rtcd_vtable; + +typedef struct +{ + unsigned int lowvalue; + unsigned int range; + unsigned int value; + int count; + const unsigned char *user_buffer; + unsigned int user_buffer_sz; + unsigned char *decode_buffer; + const unsigned char *read_ptr; + unsigned char *write_ptr; +#if CONFIG_RUNTIME_CPU_DETECT + struct vp8_dboolhuff_rtcd_vtable *rtcd; +#endif +} BOOL_DECODER; + +#define prototype_dbool_start(sym) int sym(BOOL_DECODER *br, \ + const unsigned char *source, unsigned int source_sz) +#define prototype_dbool_stop(sym) void sym(BOOL_DECODER *bc) +#define prototype_dbool_fill(sym) void sym(BOOL_DECODER *br) +#define prototype_dbool_debool(sym) int sym(BOOL_DECODER *br, int probability) +#define prototype_dbool_devalue(sym) int sym(BOOL_DECODER *br, int bits); + +#if ARCH_ARM +#include "arm/dboolhuff_arm.h" +#endif + +#ifndef vp8_dbool_start +#define vp8_dbool_start vp8dx_start_decode_c +#endif + +#ifndef vp8_dbool_stop +#define vp8_dbool_stop vp8dx_stop_decode_c +#endif + +#ifndef vp8_dbool_fill +#define vp8_dbool_fill vp8dx_bool_decoder_fill_c +#endif + +#ifndef vp8_dbool_debool +#define vp8_dbool_debool vp8dx_decode_bool_c +#endif + +#ifndef vp8_dbool_devalue +#define vp8_dbool_devalue vp8dx_decode_value_c +#endif + +extern prototype_dbool_start(vp8_dbool_start); +extern prototype_dbool_stop(vp8_dbool_stop); +extern prototype_dbool_fill(vp8_dbool_fill); +extern prototype_dbool_debool(vp8_dbool_debool); +extern prototype_dbool_devalue(vp8_dbool_devalue); + +typedef prototype_dbool_start((*vp8_dbool_start_fn_t)); +typedef prototype_dbool_stop((*vp8_dbool_stop_fn_t)); +typedef prototype_dbool_fill((*vp8_dbool_fill_fn_t)); +typedef prototype_dbool_debool((*vp8_dbool_debool_fn_t)); +typedef prototype_dbool_devalue((*vp8_dbool_devalue_fn_t)); + +typedef struct vp8_dboolhuff_rtcd_vtable { + vp8_dbool_start_fn_t start; + vp8_dbool_stop_fn_t stop; + vp8_dbool_fill_fn_t fill; + vp8_dbool_debool_fn_t debool; + vp8_dbool_devalue_fn_t devalue; +} vp8_dboolhuff_rtcd_vtable_t; + +// There are no processor-specific versions of these +// functions right now. Disable RTCD to avoid using +// function pointers which gives a speed boost +//#ifdef ENABLE_RUNTIME_CPU_DETECT +//#define DBOOLHUFF_INVOKE(ctx,fn) (ctx)->fn +//#define IF_RTCD(x) (x) +//#else +#define DBOOLHUFF_INVOKE(ctx,fn) vp8_dbool_##fn +#define IF_RTCD(x) NULL +//#endif + +static unsigned char *br_ptr_advance(const unsigned char *_ptr, + unsigned int n) +{ + uintptr_t ptr = (uintptr_t)_ptr; + + ptr += n; + ptr &= VP8_BOOL_DECODER_PTR_MASK; + + return (void *)ptr; +} + +DECLARE_ALIGNED(16, extern const unsigned int, vp8dx_bitreader_norm[256]); + +/* wrapper functions to hide RTCD. static means inline means hopefully no + * penalty + */ +static int vp8dx_start_decode(BOOL_DECODER *br, + struct vp8_dboolhuff_rtcd_vtable *rtcd, + const unsigned char *source, unsigned int source_sz) { +#if CONFIG_RUNTIME_CPU_DETECT + br->rtcd = rtcd; +#endif + return DBOOLHUFF_INVOKE(rtcd, start)(br, source, source_sz); +} +static void vp8dx_stop_decode(BOOL_DECODER *br) { + DBOOLHUFF_INVOKE(br->rtcd, stop)(br); +} +static void vp8dx_bool_decoder_fill(BOOL_DECODER *br) { + DBOOLHUFF_INVOKE(br->rtcd, fill)(br); +} +static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) { + /* + * Until optimized versions of this function are available, we + * keep the implementation in the header to allow inlining. + * + *return DBOOLHUFF_INVOKE(br->rtcd, debool)(br, probability); + */ + unsigned int bit = 0; + unsigned int split; + unsigned int bigsplit; + register unsigned int range = br->range; + register unsigned int value = br->value; + + split = 1 + (((range - 1) * probability) >> 8); + bigsplit = (split << 8); + + range = split; + + if (value >= bigsplit) + { + range = br->range - split; + value = value - bigsplit; + bit = 1; + } + + /*if(range>=0x80) + { + br->value = value; + br->range = range; + return bit + }*/ + + { + int count = br->count; + register unsigned int shift = vp8dx_bitreader_norm[range]; + range <<= shift; + value <<= shift; + count -= shift; + + if (count <= 0) + { + value |= (*br->read_ptr) << (-count); + br->read_ptr = br_ptr_advance(br->read_ptr, 1); + count += 8 ; + } + + br->count = count; + } + br->value = value; + br->range = range; + return bit; +} + +static int vp8_decode_value(BOOL_DECODER *br, int bits) +{ + /* + * Until optimized versions of this function are available, we + * keep the implementation in the header to allow inlining. + * + *return DBOOLHUFF_INVOKE(br->rtcd, devalue)(br, bits); + */ + int z = 0; + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + { + z |= (vp8dx_decode_bool(br, 0x80) << bit); + } + + return z; +} +#endif
diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c new file mode 100644 index 0000000..6035f3e --- /dev/null +++ b/vp8/decoder/decodemv.c
@@ -0,0 +1,418 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "treereader.h" +#include "entropymv.h" +#include "entropymode.h" +#include "onyxd_int.h" +#include "findnearmv.h" +#include "demode.h" +#if CONFIG_DEBUG +#include <assert.h> +#endif + +static int read_mvcomponent(vp8_reader *r, const MV_CONTEXT *mvc) +{ + const vp8_prob *const p = (const vp8_prob *) mvc; + int x = 0; + + if (vp8_read(r, p [mvpis_short])) /* Large */ + { + int i = 0; + + do + { + x += vp8_read(r, p [MVPbits + i]) << i; + } + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + { + x += vp8_read(r, p [MVPbits + i]) << i; + } + while (--i > 3); + + if (!(x & 0xFFF0) || vp8_read(r, p [MVPbits + 3])) + x += 8; + } + else /* small */ + x = vp8_treed_read(r, vp8_small_mvtree, p + MVPshort); + + if (x && vp8_read(r, p [MVPsign])) + x = -x; + + return x; +} + +static void read_mv(vp8_reader *r, MV *mv, const MV_CONTEXT *mvc) +{ + mv->row = (short)(read_mvcomponent(r, mvc) << 1); + mv->col = (short)(read_mvcomponent(r, ++mvc) << 1); +} + + +static void read_mvcontexts(vp8_reader *bc, MV_CONTEXT *mvc) +{ + int i = 0; + + do + { + const vp8_prob *up = vp8_mv_update_probs[i].prob; + vp8_prob *p = (vp8_prob *)(mvc + i); + vp8_prob *const pstop = p + MVPcount; + + do + { + if (vp8_read(bc, *up++)) + { + const vp8_prob x = (vp8_prob)vp8_read_literal(bc, 7); + + *p = x ? x << 1 : 1; + } + } + while (++p < pstop); + } + while (++i < 2); +} + + +static MB_PREDICTION_MODE read_mv_ref(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_mv_ref_tree, p); + + return (MB_PREDICTION_MODE)i; +} + +static MB_PREDICTION_MODE sub_mv_ref(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_sub_mv_ref_tree, p); + + return (MB_PREDICTION_MODE)i; +} +unsigned int vp8_mv_cont_count[5][4] = +{ + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } +}; + +void vp8_decode_mode_mvs(VP8D_COMP *pbi) +{ + const MV Zero = { 0, 0}; + + VP8_COMMON *const pc = & pbi->common; + vp8_reader *const bc = & pbi->bc; + + MODE_INFO *mi = pc->mi, *ms; + const int mis = pc->mode_info_stride; + + MV_CONTEXT *const mvc = pc->fc.mvc; + + int mb_row = -1; + + vp8_prob prob_intra; + vp8_prob prob_last; + vp8_prob prob_gf; + vp8_prob prob_skip_false = 0; + + if (pc->mb_no_coeff_skip) + prob_skip_false = (vp8_prob)vp8_read_literal(bc, 8); + + prob_intra = (vp8_prob)vp8_read_literal(bc, 8); + prob_last = (vp8_prob)vp8_read_literal(bc, 8); + prob_gf = (vp8_prob)vp8_read_literal(bc, 8); + + ms = pc->mi - 1; + + if (vp8_read_bit(bc)) + { + int i = 0; + + do + { + pc->fc.ymode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); + } + while (++i < 4); + } + + if (vp8_read_bit(bc)) + { + int i = 0; + + do + { + pc->fc.uv_mode_prob[i] = (vp8_prob) vp8_read_literal(bc, 8); + } + while (++i < 3); + } + + read_mvcontexts(bc, mvc); + + while (++mb_row < pc->mb_rows) + { + int mb_col = -1; + + while (++mb_col < pc->mb_cols) + { + MB_MODE_INFO *const mbmi = & mi->mbmi; + MV *const mv = & mbmi->mv.as_mv; + VP8_COMMON *const pc = &pbi->common; + MACROBLOCKD *xd = &pbi->mb; + + vp8dx_bool_decoder_fill(bc); + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + + // If required read in new segmentation data for this MB + if (pbi->mb.update_mb_segmentation_map) + vp8_read_mb_features(bc, mbmi, &pbi->mb); + + // Read the macroblock coeff skip flag if this feature is in use, else default to 0 + if (pc->mb_no_coeff_skip) + mbmi->mb_skip_coeff = vp8_read(bc, prob_skip_false); + else + mbmi->mb_skip_coeff = 0; + + mbmi->uv_mode = DC_PRED; + + if ((mbmi->ref_frame = (MV_REFERENCE_FRAME) vp8_read(bc, prob_intra))) /* inter MB */ + { + int rct[4]; + vp8_prob mv_ref_p [VP8_MVREFS-1]; + MV nearest, nearby, best_mv; + + if (vp8_read(bc, prob_last)) + { + mbmi->ref_frame = (MV_REFERENCE_FRAME)((int)mbmi->ref_frame + (int)(1 + vp8_read(bc, prob_gf))); + } + + vp8_find_near_mvs(xd, mi, &nearest, &nearby, &best_mv, rct, mbmi->ref_frame, pbi->common.ref_frame_sign_bias); + + vp8_mv_ref_probs(mv_ref_p, rct); + + switch (mbmi->mode = read_mv_ref(bc, mv_ref_p)) + { + case SPLITMV: + { + const int s = mbmi->partitioning = vp8_treed_read( + bc, vp8_mbsplit_tree, vp8_mbsplit_probs + ); + const int num_p = vp8_mbsplit_count [s]; + const int *const L = vp8_mbsplits [s]; + int j = 0; + + do /* for each subset j */ + { + B_MODE_INFO *const bmi = mbmi->partition_bmi + j; + MV *const mv = & bmi->mv.as_mv; + + int k = -1; /* first block in subset j */ + int mv_contz; + + while (j != L[++k]) + if (k >= 16) +#if CONFIG_DEBUG + assert(0); + +#else + ; +#endif + + mv_contz = vp8_mv_cont(&(vp8_left_bmi(mi, k)->mv.as_mv), &(vp8_above_bmi(mi, k, mis)->mv.as_mv)); + + switch (bmi->mode = (B_PREDICTION_MODE) sub_mv_ref(bc, vp8_sub_mv_ref_prob2 [mv_contz])) //pc->fc.sub_mv_ref_prob)) + { + case NEW4X4: + read_mv(bc, mv, (const MV_CONTEXT *) mvc); + mv->row += best_mv.row; + mv->col += best_mv.col; +#ifdef VPX_MODE_COUNT + vp8_mv_cont_count[mv_contz][3]++; +#endif + break; + case LEFT4X4: + *mv = vp8_left_bmi(mi, k)->mv.as_mv; +#ifdef VPX_MODE_COUNT + vp8_mv_cont_count[mv_contz][0]++; +#endif + break; + case ABOVE4X4: + *mv = vp8_above_bmi(mi, k, mis)->mv.as_mv; +#ifdef VPX_MODE_COUNT + vp8_mv_cont_count[mv_contz][1]++; +#endif + break; + case ZERO4X4: + *mv = Zero; +#ifdef VPX_MODE_COUNT + vp8_mv_cont_count[mv_contz][2]++; +#endif + break; + default: + break; + } + + /* Fill (uniform) modes, mvs of jth subset. + Must do it here because ensuing subsets can + refer back to us via "left" or "above". */ + do + if (j == L[k]) + mi->bmi[k] = *bmi; + + while (++k < 16); + } + while (++j < num_p); + } + + *mv = mi->bmi[15].mv.as_mv; + + break; /* done with SPLITMV */ + + case NEARMV: + *mv = nearby; + + // Clip "next_nearest" so that it does not extend to far out of image + if (mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; + + goto propagate_mv; + + case NEARESTMV: + *mv = nearest; + + // Clip "next_nearest" so that it does not extend to far out of image + if (mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; + + goto propagate_mv; + + case ZEROMV: + *mv = Zero; + goto propagate_mv; + + case NEWMV: + read_mv(bc, mv, (const MV_CONTEXT *) mvc); + mv->row += best_mv.row; + mv->col += best_mv.col; + /* Encoder should not produce invalid motion vectors, but since + * arbitrary length MVs can be parsed from the bitstream, we + * need to clamp them here in case we're reading bad data to + * avoid a crash. + */ +#if CONFIG_DEBUG + assert(mv->col >= (xd->mb_to_left_edge - LEFT_TOP_MARGIN)); + assert(mv->col <= (xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN)); + assert(mv->row >= (xd->mb_to_top_edge - LEFT_TOP_MARGIN)); + assert(mv->row <= (xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN)); +#endif + + if (mv->col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mv->col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mv->col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mv->col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mv->row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mv->row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mv->row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mv->row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; + + propagate_mv: /* same MV throughout */ + { + //int i=0; + //do + //{ + // mi->bmi[i].mv.as_mv = *mv; + //} + //while( ++i < 16); + + mi->bmi[0].mv.as_mv = *mv; + mi->bmi[1].mv.as_mv = *mv; + mi->bmi[2].mv.as_mv = *mv; + mi->bmi[3].mv.as_mv = *mv; + mi->bmi[4].mv.as_mv = *mv; + mi->bmi[5].mv.as_mv = *mv; + mi->bmi[6].mv.as_mv = *mv; + mi->bmi[7].mv.as_mv = *mv; + mi->bmi[8].mv.as_mv = *mv; + mi->bmi[9].mv.as_mv = *mv; + mi->bmi[10].mv.as_mv = *mv; + mi->bmi[11].mv.as_mv = *mv; + mi->bmi[12].mv.as_mv = *mv; + mi->bmi[13].mv.as_mv = *mv; + mi->bmi[14].mv.as_mv = *mv; + mi->bmi[15].mv.as_mv = *mv; + } + + break; + + default:; +#if CONFIG_DEBUG + assert(0); +#endif + } + + } + else + { + /* MB is intra coded */ + + int j = 0; + + do + { + mi->bmi[j].mv.as_mv = Zero; + } + while (++j < 16); + + *mv = Zero; + + if ((mbmi->mode = (MB_PREDICTION_MODE) vp8_read_ymode(bc, pc->fc.ymode_prob)) == B_PRED) + { + int j = 0; + + do + { + mi->bmi[j].mode = (B_PREDICTION_MODE)vp8_read_bmode(bc, pc->fc.bmode_prob); + } + while (++j < 16); + } + + mbmi->uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, pc->fc.uv_mode_prob); + } + + mi++; // next macroblock + } + + mi++; // skip left predictor each row + } +}
diff --git a/vp8/decoder/decodemv.h b/vp8/decoder/decodemv.h new file mode 100644 index 0000000..4030071 --- /dev/null +++ b/vp8/decoder/decodemv.h
@@ -0,0 +1,13 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxd_int.h" + +void vp8_decode_mode_mvs(VP8D_COMP *);
diff --git a/vp8/decoder/decoderthreading.h b/vp8/decoder/decoderthreading.h new file mode 100644 index 0000000..ebc5c27 --- /dev/null +++ b/vp8/decoder/decoderthreading.h
@@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + + + + +#ifndef _DECODER_THREADING_H +#define _DECODER_THREADING_H + + +extern void vp8_mtdecode_mb_rows(VP8D_COMP *pbi, + MACROBLOCKD *xd); +extern void vp8_stop_lfthread(VP8D_COMP *pbi); +extern void vp8_start_lfthread(VP8D_COMP *pbi); +extern void vp8_decoder_remove_threads(VP8D_COMP *pbi); +extern void vp8_decoder_create_threads(VP8D_COMP *pbi); +#endif
diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c new file mode 100644 index 0000000..4edf4f6 --- /dev/null +++ b/vp8/decoder/decodframe.c
@@ -0,0 +1,907 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxd_int.h" +#include "header.h" +#include "reconintra.h" +#include "reconintra4x4.h" +#include "recon.h" +#include "reconinter.h" +#include "dequantize.h" +#include "detokenize.h" +#include "invtrans.h" +#include "alloccommon.h" +#include "entropymode.h" +#include "quant_common.h" +#include "segmentation_common.h" +#include "setupintrarecon.h" +#include "demode.h" +#include "decodemv.h" +#include "extend.h" +#include "vpx_mem/vpx_mem.h" +#include "idct.h" +#include "dequantize.h" +#include "predictdc.h" +#include "threading.h" +#include "decoderthreading.h" +#include "dboolhuff.h" + +#include <assert.h> +#include <stdio.h> + +void vp8cx_init_de_quantizer(VP8D_COMP *pbi) +{ + int r, c; + int i; + int Q; + VP8_COMMON *const pc = & pbi->common; + + for (Q = 0; Q < QINDEX_RANGE; Q++) + { + pc->Y1dequant[Q][0][0] = (short)vp8_dc_quant(Q, pc->y1dc_delta_q); + pc->Y2dequant[Q][0][0] = (short)vp8_dc2quant(Q, pc->y2dc_delta_q); + pc->UVdequant[Q][0][0] = (short)vp8_dc_uv_quant(Q, pc->uvdc_delta_q); + + // all the ac values = ; + for (i = 1; i < 16; i++) + { + int rc = vp8_default_zig_zag1d[i]; + r = (rc >> 2); + c = (rc & 3); + + pc->Y1dequant[Q][r][c] = (short)vp8_ac_yquant(Q); + pc->Y2dequant[Q][r][c] = (short)vp8_ac2quant(Q, pc->y2ac_delta_q); + pc->UVdequant[Q][r][c] = (short)vp8_ac_uv_quant(Q, pc->uvac_delta_q); + } + } +} + +static void mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + int i; + int QIndex; + MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi; + VP8_COMMON *const pc = & pbi->common; + + // Decide whether to use the default or alternate baseline Q value. + if (xd->segmentation_enabled) + { + // Abs Value + if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) + QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + + // Delta Value + else + { + QIndex = pc->base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; // Clamp to valid range + } + } + else + QIndex = pc->base_qindex; + + // Set up the block level dequant pointers + for (i = 0; i < 16; i++) + { + xd->block[i].dequant = pc->Y1dequant[QIndex]; + } + + for (i = 16; i < 24; i++) + { + xd->block[i].dequant = pc->UVdequant[QIndex]; + } + + xd->block[24].dequant = pc->Y2dequant[QIndex]; + +} + +#if CONFIG_RUNTIME_CPU_DETECT +#define RTCD_VTABLE(x) (&(pbi)->common.rtcd.x) +#else +#define RTCD_VTABLE(x) NULL +#endif + +//skip_recon_mb() is Modified: Instead of writing the result to predictor buffer and then copying it +// to dst buffer, we can write the result directly to dst buffer. This eliminates unnecessary copy. +static void skip_recon_mb(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + if (xd->frame_type == KEY_FRAME || xd->mbmi.ref_frame == INTRA_FRAME) + { + + vp8_build_intra_predictors_mbuv_s(xd); + vp8_build_intra_predictors_mby_s_ptr(xd); + + } + else + { + vp8_build_inter_predictors_mb_s(xd); + } +} + +static void reconstruct_mb(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + if (xd->frame_type == KEY_FRAME || xd->mbmi.ref_frame == INTRA_FRAME) + { + vp8_build_intra_predictors_mbuv(xd); + + if (xd->mbmi.mode != B_PRED) + { + vp8_build_intra_predictors_mby_ptr(xd); + vp8_recon16x16mb(RTCD_VTABLE(recon), xd); + } + else + { + vp8_recon_intra4x4mb(RTCD_VTABLE(recon), xd); + } + } + else + { + vp8_build_inter_predictors_mb(xd); + vp8_recon16x16mb(RTCD_VTABLE(recon), xd); + } +} + + +static void de_quantand_idct(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + int i; + BLOCKD *b = &xd->block[24]; + + + if (xd->mbmi.mode != B_PRED && xd->mbmi.mode != SPLITMV) + { + DEQUANT_INVOKE(&pbi->dequant, block)(b); + + // do 2nd order transform on the dc block + if (b->eob > 1) + { + IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh16)(&b->dqcoeff[0], b->diff); + ((int *)b->qcoeff)[0] = 0; + ((int *)b->qcoeff)[1] = 0; + ((int *)b->qcoeff)[2] = 0; + ((int *)b->qcoeff)[3] = 0; + ((int *)b->qcoeff)[4] = 0; + ((int *)b->qcoeff)[5] = 0; + ((int *)b->qcoeff)[6] = 0; + ((int *)b->qcoeff)[7] = 0; + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), iwalsh1)(&b->dqcoeff[0], b->diff); + ((int *)b->qcoeff)[0] = 0; + } + + + for (i = 0; i < 16; i++) + { + + b = &xd->block[i]; + + if (b->eob > 1) + { + DEQUANT_INVOKE(&pbi->dequant, idct_dc)(b->qcoeff, &b->dequant[0][0], b->diff, 32, xd->block[24].diff[i]); + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), idct1_scalar)(xd->block[24].diff[i], b->diff, 32); + } + } + + for (i = 16; i < 24; i++) + { + b = &xd->block[i]; + + if (b->eob > 1) + { + DEQUANT_INVOKE(&pbi->dequant, idct)(b->qcoeff, &b->dequant[0][0], b->diff, 16); + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), idct1_scalar)(b->qcoeff[0] * b->dequant[0][0], b->diff, 16); + ((int *)b->qcoeff)[0] = 0; + } + } + } + else + { + for (i = 0; i < 24; i++) + { + + b = &xd->block[i]; + + if (b->eob > 1) + { + DEQUANT_INVOKE(&pbi->dequant, idct)(b->qcoeff, &b->dequant[0][0], b->diff, (32 - (i & 16))); + } + else + { + IDCT_INVOKE(RTCD_VTABLE(idct), idct1_scalar)(b->qcoeff[0] * b->dequant[0][0], b->diff, (32 - (i & 16))); + ((int *)b->qcoeff)[0] = 0; + } + } + } +} + +void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd) +{ + int eobtotal = 0; + + if (xd->mbmi.mb_skip_coeff) + { + vp8_reset_mb_tokens_context(xd); + } + else + { + eobtotal = vp8_decode_mb_tokens(pbi, xd); + } + + xd->mode_info_context->mbmi.dc_diff = 1; + + if (xd->mbmi.mode != B_PRED && xd->mbmi.mode != SPLITMV && eobtotal == 0) + { + xd->mode_info_context->mbmi.dc_diff = 0; + skip_recon_mb(pbi, xd); + return; + } + + if (xd->segmentation_enabled) + mb_init_dequantizer(pbi, xd); + + de_quantand_idct(pbi, xd); + reconstruct_mb(pbi, xd); +} + +static int get_delta_q(vp8_reader *bc, int prev, int *q_update) +{ + int ret_val = 0; + + if (vp8_read_bit(bc)) + { + ret_val = vp8_read_literal(bc, 4); + + if (vp8_read_bit(bc)) + ret_val = -ret_val; + } + + /* Trigger a quantizer update if the delta-q value has changed */ + if (ret_val != prev) + *q_update = 1; + + return ret_val; +} + +#ifdef PACKET_TESTING +#include <stdio.h> +FILE *vpxlog = 0; +#endif + + + +void vp8_decode_mb_row(VP8D_COMP *pbi, + VP8_COMMON *pc, + int mb_row, + MACROBLOCKD *xd) +{ + + int i; + int recon_yoffset, recon_uvoffset; + int mb_col; + int recon_y_stride = pc->last_frame.y_stride; + int recon_uv_stride = pc->last_frame.uv_stride; + + vpx_memset(pc->left_context, 0, sizeof(pc->left_context)); + recon_yoffset = mb_row * recon_y_stride * 16; + recon_uvoffset = mb_row * recon_uv_stride * 8; + // reset above block coeffs + + xd->above_context[Y1CONTEXT] = pc->above_context[Y1CONTEXT]; + xd->above_context[UCONTEXT ] = pc->above_context[UCONTEXT]; + xd->above_context[VCONTEXT ] = pc->above_context[VCONTEXT]; + xd->above_context[Y2CONTEXT] = pc->above_context[Y2CONTEXT]; + xd->up_available = (mb_row != 0); + + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + + for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) + { + // Take a copy of the mode and Mv information for this macroblock into the xd->mbmi + vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi, 32); //sizeof(MB_MODE_INFO) ); + + if (xd->mbmi.mode == SPLITMV || xd->mbmi.mode == B_PRED) + { + for (i = 0; i < 16; i++) + { + BLOCKD *d = &xd->block[i]; + vpx_memcpy(&d->bmi, &xd->mode_info_context->bmi[i], sizeof(B_MODE_INFO)); + } + } + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + + xd->dst.y_buffer = pc->new_frame.y_buffer + recon_yoffset; + xd->dst.u_buffer = pc->new_frame.u_buffer + recon_uvoffset; + xd->dst.v_buffer = pc->new_frame.v_buffer + recon_uvoffset; + + xd->left_available = (mb_col != 0); + + // Select the appropriate reference frame for this MB + if (xd->mbmi.ref_frame == LAST_FRAME) + { + xd->pre.y_buffer = pc->last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->last_frame.v_buffer + recon_uvoffset; + } + else if (xd->mbmi.ref_frame == GOLDEN_FRAME) + { + // Golden frame reconstruction buffer + xd->pre.y_buffer = pc->golden_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->golden_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->golden_frame.v_buffer + recon_uvoffset; + } + else + { + // Alternate reference frame reconstruction buffer + xd->pre.y_buffer = pc->alt_ref_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->alt_ref_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->alt_ref_frame.v_buffer + recon_uvoffset; + } + + vp8_build_uvmvs(xd, pc->full_pixel); + + /* + if(pbi->common.current_video_frame==0 &&mb_col==1 && mb_row==0) + pbi->debugoutput =1; + else + pbi->debugoutput =0; + */ + vp8dx_bool_decoder_fill(xd->current_bc); + vp8_decode_macroblock(pbi, xd); + + + recon_yoffset += 16; + recon_uvoffset += 8; + + ++xd->mode_info_context; /* next mb */ + + xd->gf_active_ptr++; // GF useage flag for next MB + + xd->above_context[Y1CONTEXT] += 4; + xd->above_context[UCONTEXT ] += 2; + xd->above_context[VCONTEXT ] += 2; + xd->above_context[Y2CONTEXT] ++; + + pbi->current_mb_col_main = mb_col; + } + + // adjust to the next row of mbs + vp8_extend_mb_row( + &pc->new_frame, + xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8 + ); + + ++xd->mode_info_context; /* skip prediction column */ + + pbi->last_mb_row_decoded = mb_row; +} + + +static unsigned int read_partition_size(const unsigned char *cx_size) +{ + const unsigned int size = + cx_size[0] + (cx_size[1] << 8) + (cx_size[2] << 16); + return size; +} + + +static void setup_token_decoder(VP8D_COMP *pbi, + const unsigned char *cx_data) +{ + int num_part; + int i; + VP8_COMMON *pc = &pbi->common; + const unsigned char *user_data_end = pbi->Source + pbi->source_sz; + vp8_reader *bool_decoder; + const unsigned char *partition; + + /* Parse number of token partitions to use */ + pc->multi_token_partition = (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2); + num_part = 1 << pc->multi_token_partition; + + /* Set up pointers to the first partition */ + partition = cx_data; + bool_decoder = &pbi->bc2; + + if (num_part > 1) + { + CHECK_MEM_ERROR(pbi->mbc, vpx_malloc(num_part * sizeof(vp8_reader))); + bool_decoder = pbi->mbc; + partition += 3 * (num_part - 1); + } + + for (i = 0; i < num_part; i++) + { + const unsigned char *partition_size_ptr = cx_data + i * 3; + unsigned int partition_size; + + /* Calculate the length of this partition. The last partition + * size is implicit. + */ + if (i < num_part - 1) + { + partition_size = read_partition_size(partition_size_ptr); + } + else + { + partition_size = user_data_end - partition; + } + + if (partition + partition_size > user_data_end) + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition " + "%d length", i + 1); + + if (vp8dx_start_decode(bool_decoder, IF_RTCD(&pbi->dboolhuff), + partition, partition_size)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate bool decoder %d", i + 1); + + /* Advance to the next partition */ + partition += partition_size; + bool_decoder++; + } + + /* Clamp number of decoder threads */ + if (pbi->decoding_thread_count > num_part - 1) + pbi->decoding_thread_count = num_part - 1; +} + + +static void stop_token_decoder(VP8D_COMP *pbi) +{ + int i; + VP8_COMMON *pc = &pbi->common; + + if (pc->multi_token_partition != ONE_PARTITION) + { + int num_part = (1 << pc->multi_token_partition); + + for (i = 0; i < num_part; i++) + { + vp8dx_stop_decode(&pbi->mbc[i]); + } + + vpx_free(pbi->mbc); + } + else + vp8dx_stop_decode(& pbi->bc2); +} + +static void init_frame(VP8D_COMP *pbi) +{ + VP8_COMMON *const pc = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + + if (pc->frame_type == KEY_FRAME) + { + // Various keyframe initializations + vpx_memcpy(pc->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + + vp8_init_mbmode_probs(pc); + + vp8_default_coef_probs(pc); + vp8_kf_default_bmode_probs(pc->kf_bmode_prob); + + // reset the segment feature data to 0 with delta coding (Default state). + vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + xd->mb_segement_abs_delta = SEGMENT_DELTADATA; + + // reset the mode ref deltasa for loop filter + vpx_memset(xd->ref_lf_deltas, 0, sizeof(xd->ref_lf_deltas)); + vpx_memset(xd->mode_lf_deltas, 0, sizeof(xd->mode_lf_deltas)); + + // All buffers are implicitly updated on key frames. + pc->refresh_golden_frame = 1; + pc->refresh_alt_ref_frame = 1; + pc->copy_buffer_to_gf = 0; + pc->copy_buffer_to_arf = 0; + + // Note that Golden and Altref modes cannot be used on a key frame so + // ref_frame_sign_bias[] is undefined and meaningless + pc->ref_frame_sign_bias[GOLDEN_FRAME] = 0; + pc->ref_frame_sign_bias[ALTREF_FRAME] = 0; + } + else + { + if (!pc->use_bilinear_mc_filter) + pc->mcomp_filter_type = SIXTAP; + else + pc->mcomp_filter_type = BILINEAR; + + // To enable choice of different interploation filters + if (pc->mcomp_filter_type == SIXTAP) + { + xd->subpixel_predict = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap4x4); + xd->subpixel_predict8x4 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap8x4); + xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap8x8); + xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), sixtap16x16); + } + else + { + xd->subpixel_predict = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear4x4); + xd->subpixel_predict8x4 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x4); + xd->subpixel_predict8x8 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear8x8); + xd->subpixel_predict16x16 = SUBPIX_INVOKE(RTCD_VTABLE(subpix), bilinear16x16); + } + } + + xd->left_context = pc->left_context; + xd->mode_info_context = pc->mi; + xd->frame_type = pc->frame_type; + xd->mbmi.mode = DC_PRED; + xd->mode_info_stride = pc->mode_info_stride; +} + +int vp8_decode_frame(VP8D_COMP *pbi) +{ + vp8_reader *const bc = & pbi->bc; + VP8_COMMON *const pc = & pbi->common; + MACROBLOCKD *const xd = & pbi->mb; + const unsigned char *data = (const unsigned char *)pbi->Source; + const unsigned char *const data_end = data + pbi->source_sz; + int first_partition_length_in_bytes; + + int mb_row; + int i, j, k, l; + const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; + + pc->frame_type = (FRAME_TYPE)(data[0] & 1); + pc->version = (data[0] >> 1) & 7; + pc->show_frame = (data[0] >> 4) & 1; + first_partition_length_in_bytes = + (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5; + data += 3; + + if (data + first_partition_length_in_bytes > data_end) + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Truncated packet or corrupt partition 0 length"); + vp8_setup_version(pc); + + if (pc->frame_type == KEY_FRAME) + { + const int Width = pc->Width; + const int Height = pc->Height; + + // vet via sync code + if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a) + vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, + "Invalid frame sync code"); + + pc->Width = (data[3] | (data[4] << 8)) & 0x3fff; + pc->horiz_scale = data[4] >> 6; + pc->Height = (data[5] | (data[6] << 8)) & 0x3fff; + pc->vert_scale = data[6] >> 6; + data += 7; + + if (Width != pc->Width || Height != pc->Height) + { + if (pc->Width <= 0) + { + pc->Width = Width; + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Invalid frame width"); + } + + if (pc->Height <= 0) + { + pc->Height = Height; + vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, + "Invalid frame height"); + } + + if (vp8_alloc_frame_buffers(&pbi->common, pc->Width, pc->Height)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate frame buffers"); + } + } + + if (pc->Width == 0 || pc->Height == 0) + { + return -1; + } + + init_frame(pbi); + + if (vp8dx_start_decode(bc, IF_RTCD(&pbi->dboolhuff), + data, data_end - data)) + vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, + "Failed to allocate bool decoder 0"); + if (pc->frame_type == KEY_FRAME) { + pc->clr_type = (YUV_TYPE)vp8_read_bit(bc); + pc->clamp_type = (CLAMP_TYPE)vp8_read_bit(bc); + } + + // Is segmentation enabled + xd->segmentation_enabled = (unsigned char)vp8_read_bit(bc); + + if (xd->segmentation_enabled) + { + // Signal whether or not the segmentation map is being explicitly updated this frame. + xd->update_mb_segmentation_map = (unsigned char)vp8_read_bit(bc); + xd->update_mb_segmentation_data = (unsigned char)vp8_read_bit(bc); + + if (xd->update_mb_segmentation_data) + { + xd->mb_segement_abs_delta = (unsigned char)vp8_read_bit(bc); + + vpx_memset(xd->segment_feature_data, 0, sizeof(xd->segment_feature_data)); + + // For each segmentation feature (Quant and loop filter level) + for (i = 0; i < MB_LVL_MAX; i++) + { + for (j = 0; j < MAX_MB_SEGMENTS; j++) + { + // Frame level data + if (vp8_read_bit(bc)) + { + xd->segment_feature_data[i][j] = (signed char)vp8_read_literal(bc, mb_feature_data_bits[i]); + + if (vp8_read_bit(bc)) + xd->segment_feature_data[i][j] = -xd->segment_feature_data[i][j]; + } + else + xd->segment_feature_data[i][j] = 0; + } + } + } + + if (xd->update_mb_segmentation_map) + { + // Which macro block level features are enabled + vpx_memset(xd->mb_segment_tree_probs, 255, sizeof(xd->mb_segment_tree_probs)); + + // Read the probs used to decode the segment id for each macro block. + for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) + { + // If not explicitly set value is defaulted to 255 by memset above + if (vp8_read_bit(bc)) + xd->mb_segment_tree_probs[i] = (vp8_prob)vp8_read_literal(bc, 8); + } + } + } + + // Read the loop filter level and type + pc->filter_type = (LOOPFILTERTYPE) vp8_read_bit(bc); + pc->filter_level = vp8_read_literal(bc, 6); + pc->sharpness_level = vp8_read_literal(bc, 3); + + // Read in loop filter deltas applied at the MB level based on mode or ref frame. + xd->mode_ref_lf_delta_update = 0; + xd->mode_ref_lf_delta_enabled = (unsigned char)vp8_read_bit(bc); + + if (xd->mode_ref_lf_delta_enabled) + { + // Do the deltas need to be updated + xd->mode_ref_lf_delta_update = (unsigned char)vp8_read_bit(bc); + + if (xd->mode_ref_lf_delta_update) + { + // Send update + for (i = 0; i < MAX_REF_LF_DELTAS; i++) + { + if (vp8_read_bit(bc)) + { + //sign = vp8_read_bit( bc ); + xd->ref_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6); + + if (vp8_read_bit(bc)) // Apply sign + xd->ref_lf_deltas[i] = xd->ref_lf_deltas[i] * -1; + } + } + + // Send update + for (i = 0; i < MAX_MODE_LF_DELTAS; i++) + { + if (vp8_read_bit(bc)) + { + //sign = vp8_read_bit( bc ); + xd->mode_lf_deltas[i] = (signed char)vp8_read_literal(bc, 6); + + if (vp8_read_bit(bc)) // Apply sign + xd->mode_lf_deltas[i] = xd->mode_lf_deltas[i] * -1; + } + } + } + } + + setup_token_decoder(pbi, data + first_partition_length_in_bytes); + xd->current_bc = &pbi->bc2; + + // Read the default quantizers. + { + int Q, q_update; + + Q = vp8_read_literal(bc, 7); // AC 1st order Q = default + pc->base_qindex = Q; + q_update = 0; + pc->y1dc_delta_q = get_delta_q(bc, pc->y1dc_delta_q, &q_update); + pc->y2dc_delta_q = get_delta_q(bc, pc->y2dc_delta_q, &q_update); + pc->y2ac_delta_q = get_delta_q(bc, pc->y2ac_delta_q, &q_update); + pc->uvdc_delta_q = get_delta_q(bc, pc->uvdc_delta_q, &q_update); + pc->uvac_delta_q = get_delta_q(bc, pc->uvac_delta_q, &q_update); + + if (q_update) + vp8cx_init_de_quantizer(pbi); + + // MB level dequantizer setup + mb_init_dequantizer(pbi, &pbi->mb); + } + + // Determine if the golden frame or ARF buffer should be updated and how. + // For all non key frames the GF and ARF refresh flags and sign bias + // flags must be set explicitly. + if (pc->frame_type != KEY_FRAME) + { + // Should the GF or ARF be updated from the current frame + pc->refresh_golden_frame = vp8_read_bit(bc); + pc->refresh_alt_ref_frame = vp8_read_bit(bc); + + // Buffer to buffer copy flags. + pc->copy_buffer_to_gf = 0; + + if (!pc->refresh_golden_frame) + pc->copy_buffer_to_gf = vp8_read_literal(bc, 2); + + pc->copy_buffer_to_arf = 0; + + if (!pc->refresh_alt_ref_frame) + pc->copy_buffer_to_arf = vp8_read_literal(bc, 2); + + pc->ref_frame_sign_bias[GOLDEN_FRAME] = vp8_read_bit(bc); + pc->ref_frame_sign_bias[ALTREF_FRAME] = vp8_read_bit(bc); + } + + pc->refresh_entropy_probs = vp8_read_bit(bc); + if (pc->refresh_entropy_probs == 0) + { + vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); + } + + pc->refresh_last_frame = pc->frame_type == KEY_FRAME || vp8_read_bit(bc); + + if (0) + { + FILE *z = fopen("decodestats.stt", "a"); + fprintf(z, "%6d F:%d,G:%d,A:%d,L:%d,Q:%d\n", + pc->current_video_frame, + pc->frame_type, + pc->refresh_golden_frame, + pc->refresh_alt_ref_frame, + pc->refresh_last_frame, + pc->base_qindex); + fclose(z); + } + + + vp8dx_bool_decoder_fill(bc); + { + // read coef probability tree + + for (i = 0; i < BLOCK_TYPES; i++) + for (j = 0; j < COEF_BANDS; j++) + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + for (l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) + { + + vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l; + + if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l])) + { + *p = (vp8_prob)vp8_read_literal(bc, 8); + + } + } + } + + vpx_memcpy(&xd->pre, &pc->last_frame, sizeof(YV12_BUFFER_CONFIG)); + vpx_memcpy(&xd->dst, &pc->new_frame, sizeof(YV12_BUFFER_CONFIG)); + + // set up frame new frame for intra coded blocks + vp8_setup_intra_recon(&pc->new_frame); + + vp8_setup_block_dptrs(xd); + + vp8_build_block_doffsets(xd); + + // clear out the coeff buffer + vpx_memset(xd->qcoeff, 0, sizeof(xd->qcoeff)); + + // Read the mb_no_coeff_skip flag + pc->mb_no_coeff_skip = (int)vp8_read_bit(bc); + + if (pc->frame_type == KEY_FRAME) + vp8_kfread_modes(pbi); + else + vp8_decode_mode_mvs(pbi); + + // reset since these guys are used as iterators + vpx_memset(pc->above_context[Y1CONTEXT], 0, sizeof(ENTROPY_CONTEXT) * pc->mb_cols * 4); + vpx_memset(pc->above_context[UCONTEXT ], 0, sizeof(ENTROPY_CONTEXT) * pc->mb_cols * 2); + vpx_memset(pc->above_context[VCONTEXT ], 0, sizeof(ENTROPY_CONTEXT) * pc->mb_cols * 2); + vpx_memset(pc->above_context[Y2CONTEXT], 0, sizeof(ENTROPY_CONTEXT) * pc->mb_cols); + + xd->gf_active_ptr = (signed char *)pc->gf_active_flags; // Point to base of GF active flags data structure + + + vpx_memcpy(&xd->block[0].bmi, &xd->mode_info_context->bmi[0], sizeof(B_MODE_INFO)); + + + if (pbi->b_multithreaded_lf && pbi->common.filter_level != 0) + vp8_start_lfthread(pbi); + + if (pbi->b_multithreaded_rd && pbi->common.multi_token_partition != ONE_PARTITION) + { + vp8_mtdecode_mb_rows(pbi, xd); + } + else + { + int ibc = 0; + int num_part = 1 << pbi->common.multi_token_partition; + + // Decode the individual macro block + for (mb_row = 0; mb_row < pc->mb_rows; mb_row++) + { + + if (num_part > 1) + { + xd->current_bc = & pbi->mbc[ibc]; + ibc++; + + if (ibc == num_part) + ibc = 0; + } + + vp8_decode_mb_row(pbi, pc, mb_row, xd); + } + + pbi->last_mb_row_decoded = mb_row; + } + + + stop_token_decoder(pbi); + + vp8dx_stop_decode(bc); + + // vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes \n",bc->pos+pbi->bc2.pos); + + // If this was a kf or Gf note the Q used + if ((pc->frame_type == KEY_FRAME) || (pc->refresh_golden_frame) || pbi->common.refresh_alt_ref_frame) + pc->last_kf_gf_q = pc->base_qindex; + + if (pc->refresh_entropy_probs == 0) + { + vpx_memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); + } + +#ifdef PACKET_TESTING + { + FILE *f = fopen("decompressor.VP8", "ab"); + unsigned int size = pbi->bc2.pos + pbi->bc.pos + 8; + fwrite((void *) &size, 4, 1, f); + fwrite((void *) pbi->Source, size, 1, f); + fclose(f); + } +#endif + + return 0; +}
diff --git a/vp8/decoder/demode.c b/vp8/decoder/demode.c new file mode 100644 index 0000000..fd05e6d --- /dev/null +++ b/vp8/decoder/demode.c
@@ -0,0 +1,149 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxd_int.h" +#include "entropymode.h" +#include "findnearmv.h" + + +int vp8_read_bmode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_bmode_tree, p); + + return i; +} + + +int vp8_read_ymode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_ymode_tree, p); + + return i; +} + +int vp8_kfread_ymode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_kf_ymode_tree, p); + + return i; +} + + + +int vp8_read_uv_mode(vp8_reader *bc, const vp8_prob *p) +{ + const int i = vp8_treed_read(bc, vp8_uv_mode_tree, p); + + return i; +} + +void vp8_read_mb_features(vp8_reader *r, MB_MODE_INFO *mi, MACROBLOCKD *x) +{ + // Is segmentation enabled + if (x->segmentation_enabled && x->update_mb_segmentation_map) + { + // If so then read the segment id. + if (vp8_read(r, x->mb_segment_tree_probs[0])) + mi->segment_id = (unsigned char)(2 + vp8_read(r, x->mb_segment_tree_probs[2])); + else + mi->segment_id = (unsigned char)(vp8_read(r, x->mb_segment_tree_probs[1])); + } +} + +void vp8_kfread_modes(VP8D_COMP *pbi) +{ + VP8_COMMON *const cp = & pbi->common; + vp8_reader *const bc = & pbi->bc; + + MODE_INFO *m = cp->mi; + const int ms = cp->mode_info_stride; + + int mb_row = -1; + vp8_prob prob_skip_false = 0; + + if (cp->mb_no_coeff_skip) + prob_skip_false = (vp8_prob)(vp8_read_literal(bc, 8)); + + while (++mb_row < cp->mb_rows) + { + int mb_col = -1; + + while (++mb_col < cp->mb_cols) + { + MB_PREDICTION_MODE y_mode; + + vp8dx_bool_decoder_fill(bc); + // Read the Macroblock segmentation map if it is being updated explicitly this frame (reset to 0 above by default) + // By default on a key frame reset all MBs to segment 0 + m->mbmi.segment_id = 0; + + if (pbi->mb.update_mb_segmentation_map) + vp8_read_mb_features(bc, &m->mbmi, &pbi->mb); + + // Read the macroblock coeff skip flag if this feature is in use, else default to 0 + if (cp->mb_no_coeff_skip) + m->mbmi.mb_skip_coeff = vp8_read(bc, prob_skip_false); + else + m->mbmi.mb_skip_coeff = 0; + + y_mode = (MB_PREDICTION_MODE) vp8_kfread_ymode(bc, cp->kf_ymode_prob); + + m->mbmi.ref_frame = INTRA_FRAME; + + if ((m->mbmi.mode = y_mode) == B_PRED) + { + int i = 0; + + do + { + const B_PREDICTION_MODE A = vp8_above_bmi(m, i, ms)->mode; + const B_PREDICTION_MODE L = vp8_left_bmi(m, i)->mode; + + m->bmi[i].mode = (B_PREDICTION_MODE) vp8_read_bmode(bc, cp->kf_bmode_prob [A] [L]); + } + while (++i < 16); + } + else + { + int BMode; + int i = 0; + + switch (y_mode) + { + case DC_PRED: + BMode = B_DC_PRED; + break; + case V_PRED: + BMode = B_VE_PRED; + break; + case H_PRED: + BMode = B_HE_PRED; + break; + case TM_PRED: + BMode = B_TM_PRED; + break; + default: + BMode = B_DC_PRED; + break; + } + + do + { + m->bmi[i].mode = (B_PREDICTION_MODE)BMode; + } + while (++i < 16); + } + + (m++)->mbmi.uv_mode = (MB_PREDICTION_MODE)vp8_read_uv_mode(bc, cp->kf_uv_mode_prob); + } + + m++; // skip the border + } +}
diff --git a/vp8/decoder/demode.h b/vp8/decoder/demode.h new file mode 100644 index 0000000..51bbc5e --- /dev/null +++ b/vp8/decoder/demode.h
@@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxd_int.h" + +/* Read (intra) modes for all blocks in a keyframe */ + +void vp8_kfread_modes(VP8D_COMP *pbi); + +/* Intra mode for a Y subblock */ + +int vp8_read_bmode(vp8_reader *, const vp8_prob *); + +/* MB intra Y mode trees differ for key and inter frames. */ + +int vp8_read_ymode(vp8_reader *, const vp8_prob *); +int vp8_kfread_ymode(vp8_reader *, const vp8_prob *); + +/* MB intra UV mode trees are the same for key and inter frames. */ + +int vp8_read_uv_mode(vp8_reader *, const vp8_prob *); + +/* Read any macroblock-level features that may be present. */ + +void vp8_read_mb_features(vp8_reader *, MB_MODE_INFO *, MACROBLOCKD *);
diff --git a/vp8/decoder/dequantize.c b/vp8/decoder/dequantize.c new file mode 100644 index 0000000..14798d9 --- /dev/null +++ b/vp8/decoder/dequantize.c
@@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "dequantize.h" +#include "predictdc.h" +#include "idct.h" +#include "vpx_mem/vpx_mem.h" + +extern void vp8_short_idct4x4llm_c(short *input, short *output, int pitch) ; +extern void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); + + +void vp8_dequantize_b_c(BLOCKD *d) +{ + int i; + short *DQ = d->dqcoeff; + short *Q = d->qcoeff; + short *DQC = &d->dequant[0][0]; + + for (i = 0; i < 16; i++) + { + DQ[i] = Q[i] * DQC[i]; + } +} + +void vp8_dequant_idct_c(short *input, short *dq, short *output, int pitch) +{ + int i; + + for (i = 0; i < 16; i++) + { + input[i] = dq[i] * input[i]; + } + + vp8_short_idct4x4llm_c(input, output, pitch); + vpx_memset(input, 0, 32); +} + +void vp8_dequant_dc_idct_c(short *input, short *dq, short *output, int pitch, int Dc) +{ + int i; + + input[0] = (short)Dc; + + for (i = 1; i < 16; i++) + { + input[i] = dq[i] * input[i]; + } + + vp8_short_idct4x4llm_c(input, output, pitch); + vpx_memset(input, 0, 32); +}
diff --git a/vp8/decoder/dequantize.h b/vp8/decoder/dequantize.h new file mode 100644 index 0000000..d16b02e --- /dev/null +++ b/vp8/decoder/dequantize.h
@@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DEQUANTIZE_H +#define DEQUANTIZE_H +#include "blockd.h" + +#define prototype_dequant_block(sym) \ + void sym(BLOCKD *x) + +#define prototype_dequant_idct(sym) \ + void sym(short *input, short *dq, short *output, int pitch) + +#define prototype_dequant_idct_dc(sym) \ + void sym(short *input, short *dq, short *output, int pitch, int dc) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/dequantize_x86.h" +#endif + +#if ARCH_ARM +#include "arm/dequantize_arm.h" +#endif + +#ifndef vp8_dequant_block +#define vp8_dequant_block vp8_dequantize_b_c +#endif +extern prototype_dequant_block(vp8_dequant_block); + +#ifndef vp8_dequant_idct +#define vp8_dequant_idct vp8_dequant_idct_c +#endif +extern prototype_dequant_idct(vp8_dequant_idct); + +#ifndef vp8_dequant_idct_dc +#define vp8_dequant_idct_dc vp8_dequant_dc_idct_c +#endif +extern prototype_dequant_idct_dc(vp8_dequant_idct_dc); + + +typedef prototype_dequant_block((*vp8_dequant_block_fn_t)); +typedef prototype_dequant_idct((*vp8_dequant_idct_fn_t)); +typedef prototype_dequant_idct_dc((*vp8_dequant_idct_dc_fn_t)); +typedef struct +{ + vp8_dequant_block_fn_t block; + vp8_dequant_idct_fn_t idct; + vp8_dequant_idct_dc_fn_t idct_dc; +} vp8_dequant_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define DEQUANT_INVOKE(ctx,fn) (ctx)->fn +#else +#define DEQUANT_INVOKE(ctx,fn) vp8_dequant_##fn +#endif + +#endif
diff --git a/vp8/decoder/detokenize.c b/vp8/decoder/detokenize.c new file mode 100644 index 0000000..a42f18d --- /dev/null +++ b/vp8/decoder/detokenize.c
@@ -0,0 +1,374 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "type_aliases.h" +#include "blockd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_ports/mem.h" + +#define BR_COUNT 8 +#define BOOL_DATA UINT8 + +#define OCB_X PREV_COEF_CONTEXTS * ENTROPY_NODES +DECLARE_ALIGNED(16, UINT16, vp8_coef_bands_x[16]) = { 0, 1 * OCB_X, 2 * OCB_X, 3 * OCB_X, 6 * OCB_X, 4 * OCB_X, 5 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 6 * OCB_X, 7 * OCB_X}; +#define EOB_CONTEXT_NODE 0 +#define ZERO_CONTEXT_NODE 1 +#define ONE_CONTEXT_NODE 2 +#define LOW_VAL_CONTEXT_NODE 3 +#define TWO_CONTEXT_NODE 4 +#define THREE_CONTEXT_NODE 5 +#define HIGH_LOW_CONTEXT_NODE 6 +#define CAT_ONE_CONTEXT_NODE 7 +#define CAT_THREEFOUR_CONTEXT_NODE 8 +#define CAT_THREE_CONTEXT_NODE 9 +#define CAT_FIVE_CONTEXT_NODE 10 + +/* +//the definition is put in "onyxd_int.h" +typedef struct +{ + INT16 min_val; + INT16 Length; + UINT8 Probs[12]; +} TOKENEXTRABITS; +*/ + +DECLARE_ALIGNED(16, static const TOKENEXTRABITS, vp8d_token_extra_bits2[MAX_ENTROPY_TOKENS]) = +{ + { 0, -1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //ZERO_TOKEN + { 1, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //ONE_TOKEN + { 2, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //TWO_TOKEN + { 3, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //THREE_TOKEN + { 4, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //FOUR_TOKEN + { 5, 0, { 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY1 + { 7, 1, { 145, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY2 + { 11, 2, { 140, 148, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY3 + { 19, 3, { 135, 140, 155, 176, 0, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY4 + { 35, 4, { 130, 134, 141, 157, 180, 0, 0, 0, 0, 0, 0, 0 } }, //DCT_VAL_CATEGORY5 + { 67, 10, { 129, 130, 133, 140, 153, 177, 196, 230, 243, 254, 254, 0 } }, //DCT_VAL_CATEGORY6 + { 0, -1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // EOB TOKEN +}; + + +void vp8_reset_mb_tokens_context(MACROBLOCKD *x) +{ + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + for (i = 0; i < 24; i++) + { + + a = A[ vp8_block2context[i] ] + vp8_block2above[i]; + l = L[ vp8_block2context[i] ] + vp8_block2left[i]; + + *a = *l = 0; + } + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + a = A[Y2CONTEXT] + vp8_block2above[24]; + l = L[Y2CONTEXT] + vp8_block2left[24]; + *a = *l = 0; + } + + +} +DECLARE_ALIGNED(16, extern const unsigned int, vp8dx_bitreader_norm[256]); +#define NORMALIZE \ + /*if(range < 0x80)*/ \ + { \ + shift = vp8dx_bitreader_norm[range]; \ + range <<= shift; \ + value <<= shift; \ + count -= shift; \ + if(count <= 0) \ + { \ + count += BR_COUNT ; \ + value |= (*bufptr) << (BR_COUNT-count); \ + bufptr = br_ptr_advance(bufptr, 1); \ + } \ + } + +#define DECODE_AND_APPLYSIGN(value_to_sign) \ + split = (range + 1) >> 1; \ + if ( (value >> 8) < split ) \ + { \ + range = split; \ + v= value_to_sign; \ + } \ + else \ + { \ + range = range-split; \ + value = value-(split<<8); \ + v = -value_to_sign; \ + } \ + range +=range; \ + value +=value; \ + if (!--count) \ + { \ + count = BR_COUNT; \ + value |= *bufptr; \ + bufptr = br_ptr_advance(bufptr, 1); \ + } + +#define DECODE_AND_BRANCH_IF_ZERO(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) )>> 8); \ + if ( (value >> 8) < split ) \ + { \ + range = split; \ + NORMALIZE \ + goto branch; \ + } \ + value -= (split<<8); \ + range = range - split; \ + NORMALIZE \ + } + +#define DECODE_AND_LOOP_IF_ZERO(probability,branch) \ + { \ + split = 1 + ((( probability*(range-1) ) ) >> 8); \ + if ( (value >> 8) < split ) \ + { \ + range = split; \ + NORMALIZE \ + Prob = coef_probs; \ + if(c<15) {\ + ++c; \ + Prob += vp8_coef_bands_x[c]; \ + goto branch; \ + } goto BLOCK_FINISHED; /*for malformed input */\ + } \ + value -= (split<<8); \ + range = range - split; \ + NORMALIZE \ + } + +#define DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val) \ + DECODE_AND_APPLYSIGN(val) \ + Prob = coef_probs + (ENTROPY_NODES*2); \ + if(c < 15){\ + qcoeff_ptr [ scan[c] ] = (INT16) v; \ + ++c; \ + goto DO_WHILE; }\ + qcoeff_ptr [ scan[15] ] = (INT16) v; \ + goto BLOCK_FINISHED; + + +#define DECODE_EXTRABIT_AND_ADJUST_VAL(t,bits_count)\ + split = 1 + (((range-1) * vp8d_token_extra_bits2[t].Probs[bits_count]) >> 8); \ + if(value >= (split<<8))\ + {\ + range = range-split;\ + value = value-(split<<8);\ + val += ((UINT16)1<<bits_count);\ + }\ + else\ + {\ + range = split;\ + }\ + NORMALIZE + +int vp8_decode_mb_tokens(VP8D_COMP *dx, MACROBLOCKD *x) +{ + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + const VP8_COMMON *const oc = & dx->common; + + BOOL_DECODER *bc = x->current_bc; + + ENTROPY_CONTEXT *a; + ENTROPY_CONTEXT *l; + int i; + + int eobtotal = 0; + + register int count; + + const BOOL_DATA *bufptr; + register unsigned int range; + register unsigned int value; + const int *scan; + register unsigned int shift; + UINT32 split; + INT16 *qcoeff_ptr; + + const vp8_prob *coef_probs; + int type; + int stop; + INT16 val, bits_count; + INT16 c; + INT16 t; + INT16 v; + const vp8_prob *Prob; + + //int *scan; + type = 3; + i = 0; + stop = 16; + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + i = 24; + stop = 24; + type = 1; + qcoeff_ptr = &x->qcoeff[24*16]; + scan = vp8_default_zig_zag1d; + eobtotal -= 16; + } + else + { + scan = vp8_default_zig_zag1d; + qcoeff_ptr = &x->qcoeff[0]; + } + + count = bc->count; + range = bc->range; + value = bc->value; + bufptr = bc->read_ptr; + + + coef_probs = oc->fc.coef_probs [type] [ 0 ] [0]; + +BLOCK_LOOP: + a = A[ vp8_block2context[i] ] + vp8_block2above[i]; + l = L[ vp8_block2context[i] ] + vp8_block2left[i]; + c = (INT16)(!type); + + VP8_COMBINEENTROPYCONTEXTS(t, *a, *l); + Prob = coef_probs; + Prob += t * ENTROPY_NODES; + +DO_WHILE: + Prob += vp8_coef_bands_x[c]; + DECODE_AND_BRANCH_IF_ZERO(Prob[EOB_CONTEXT_NODE], BLOCK_FINISHED); + +CHECK_0_: + DECODE_AND_LOOP_IF_ZERO(Prob[ZERO_CONTEXT_NODE], CHECK_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[ONE_CONTEXT_NODE], ONE_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[LOW_VAL_CONTEXT_NODE], LOW_VAL_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[HIGH_LOW_CONTEXT_NODE], HIGH_LOW_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREEFOUR_CONTEXT_NODE], CAT_THREEFOUR_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_FIVE_CONTEXT_NODE], CAT_FIVE_CONTEXT_NODE_0_); + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY6].min_val; + bits_count = vp8d_token_extra_bits2[DCT_VAL_CATEGORY6].Length; + + do + { + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY6, bits_count); + bits_count -- ; + } + while (bits_count >= 0); + + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_FIVE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY5].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 4); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY5, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_THREEFOUR_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_THREE_CONTEXT_NODE], CAT_THREE_CONTEXT_NODE_0_); + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY4].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 3); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY4, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_THREE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY3].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 2); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY3, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +HIGH_LOW_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[CAT_ONE_CONTEXT_NODE], CAT_ONE_CONTEXT_NODE_0_); + + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY2].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY2, 1); + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY2, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +CAT_ONE_CONTEXT_NODE_0_: + val = vp8d_token_extra_bits2[DCT_VAL_CATEGORY1].min_val; + DECODE_EXTRABIT_AND_ADJUST_VAL(DCT_VAL_CATEGORY1, 0); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(val); + +LOW_VAL_CONTEXT_NODE_0_: + DECODE_AND_BRANCH_IF_ZERO(Prob[TWO_CONTEXT_NODE], TWO_CONTEXT_NODE_0_); + DECODE_AND_BRANCH_IF_ZERO(Prob[THREE_CONTEXT_NODE], THREE_CONTEXT_NODE_0_); + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(4); + +THREE_CONTEXT_NODE_0_: + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(3); + +TWO_CONTEXT_NODE_0_: + DECODE_SIGN_WRITE_COEFF_AND_CHECK_EXIT(2); + +ONE_CONTEXT_NODE_0_: + DECODE_AND_APPLYSIGN(1); + Prob = coef_probs + ENTROPY_NODES; + + if (c < 15) + { + qcoeff_ptr [ scan[c] ] = (INT16) v; + ++c; + goto DO_WHILE; + } + + qcoeff_ptr [ scan[15] ] = (INT16) v; +BLOCK_FINISHED: + t = ((x->block[i].eob = c) != !type); // any nonzero data? + eobtotal += x->block[i].eob; + *a = *l = t; + qcoeff_ptr += 16; + + i++; + + if (i < stop) + goto BLOCK_LOOP; + + if (i == 25) + { + scan = vp8_default_zig_zag1d;//x->scan_order1d; + type = 0; + i = 0; + stop = 16; + coef_probs = oc->fc.coef_probs [type] [ 0 ] [0]; + qcoeff_ptr = &x->qcoeff[0]; + goto BLOCK_LOOP; + } + + if (i == 16) + { + type = 2; + coef_probs = oc->fc.coef_probs [type] [ 0 ] [0]; + stop = 24; + goto BLOCK_LOOP; + } + + bc->count = count; + bc->value = value; + bc->range = range; + bc->read_ptr = bufptr; + return eobtotal; + +}
diff --git a/vp8/decoder/detokenize.h b/vp8/decoder/detokenize.h new file mode 100644 index 0000000..6a9a476 --- /dev/null +++ b/vp8/decoder/detokenize.h
@@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef detokenize_h +#define detokenize_h 1 + +#include "onyxd_int.h" + +void vp8_reset_mb_tokens_context(MACROBLOCKD *x); +int vp8_decode_mb_tokens(VP8D_COMP *, MACROBLOCKD *); + +#endif /* detokenize_h */
diff --git a/vp8/decoder/generic/dsystemdependent.c b/vp8/decoder/generic/dsystemdependent.c new file mode 100644 index 0000000..302b64b --- /dev/null +++ b/vp8/decoder/generic/dsystemdependent.c
@@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "dequantize.h" +#include "onyxd_int.h" + +extern void vp8_arch_x86_decode_init(VP8D_COMP *pbi); + +void vp8_dmachine_specific_config(VP8D_COMP *pbi) +{ + // Pure C: +#if CONFIG_RUNTIME_CPU_DETECT + pbi->mb.rtcd = &pbi->common.rtcd; + pbi->dequant.block = vp8_dequantize_b_c; + pbi->dequant.idct = vp8_dequant_idct_c; + pbi->dequant.idct_dc = vp8_dequant_dc_idct_c; + pbi->dboolhuff.start = vp8dx_start_decode_c; + pbi->dboolhuff.stop = vp8dx_stop_decode_c; + pbi->dboolhuff.fill = vp8dx_bool_decoder_fill_c; +#if 0 //For use with RTCD, when implemented + pbi->dboolhuff.debool = vp8dx_decode_bool_c; + pbi->dboolhuff.devalue = vp8dx_decode_value_c; +#endif +#endif + +#if ARCH_X86 || ARCH_X86_64 + vp8_arch_x86_decode_init(pbi); +#endif +}
diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c new file mode 100644 index 0000000..6875585 --- /dev/null +++ b/vp8/decoder/onyxd_if.c
@@ -0,0 +1,451 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxc_int.h" +#if CONFIG_POSTPROC +#include "postproc.h" +#endif +#include "onyxd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "alloccommon.h" +#include "vpx_scale/yv12extend.h" +#include "loopfilter.h" +#include "swapyv12buffer.h" +#include "g_common.h" +#include "threading.h" +#include "decoderthreading.h" +#include <stdio.h> +#include "segmentation_common.h" +#include "quant_common.h" +#include "vpx_scale/vpxscale.h" +#include "systemdependent.h" +#include "vpx_ports/vpx_timer.h" + + +extern void vp8_init_loop_filter(VP8_COMMON *cm); + +extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); + +// DEBUG code +#if CONFIG_DEBUG +void vp8_recon_write_yuv_frame(unsigned char *name, YV12_BUFFER_CONFIG *s) +{ + FILE *yuv_file = fopen((char *)name, "ab"); + unsigned char *src = s->y_buffer; + int h = s->y_height; + + do + { + fwrite(src, s->y_width, 1, yuv_file); + src += s->y_stride; + } + while (--h); + + src = s->u_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + src = s->v_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + fclose(yuv_file); +} +#endif + +void vp8dx_initialize() +{ + static int init_done = 0; + + if (!init_done) + { + vp8_initialize_common(); + vp8_scale_machine_specific_config(); + init_done = 1; + } +} + + +VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) +{ + VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); + + if (!pbi) + return NULL; + + vpx_memset(pbi, 0, sizeof(VP8D_COMP)); + + if (setjmp(pbi->common.error.jmp)) + { + pbi->common.error.setjmp = 0; + vp8dx_remove_decompressor(pbi); + return 0; + } + + pbi->common.error.setjmp = 1; + vp8dx_initialize(); + + vp8_create_common(&pbi->common); + vp8_dmachine_specific_config(pbi); + + pbi->common.current_video_frame = 0; + pbi->ready_for_new_data = 1; + + pbi->CPUFreq = 0; //vp8_get_processor_freq(); + pbi->max_threads = oxcf->max_threads; + vp8_decoder_create_threads(pbi); + + //vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid + // unnecessary calling of vp8cx_init_de_quantizer() for every frame. + vp8cx_init_de_quantizer(pbi); + + { + VP8_COMMON *cm = &pbi->common; + + vp8_init_loop_filter(cm); + cm->last_frame_type = KEY_FRAME; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + } + + pbi->common.error.setjmp = 0; + return (VP8D_PTR) pbi; +} + + +void vp8dx_remove_decompressor(VP8D_PTR ptr) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + + if (!pbi) + return; + + vp8_decoder_remove_threads(pbi); + vp8_remove_common(&pbi->common); + vpx_free(pbi); +} + + +void vp8dx_set_setting(VP8D_PTR comp, VP8D_SETTING oxst, int x) +{ + VP8D_COMP *pbi = (VP8D_COMP *) comp; + + (void) pbi; + (void) x; + + switch (oxst) + { + case VP8D_OK: + break; + } +} + +int vp8dx_get_setting(VP8D_PTR comp, VP8D_SETTING oxst) +{ + VP8D_COMP *pbi = (VP8D_COMP *) comp; + + (void) pbi; + + switch (oxst) + { + case VP8D_OK: + break; + } + + return -1; +} + +int vp8dx_get_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(&cm->last_frame, sd); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, sd); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, sd); + + else + return -1; + + return 0; +} +int vp8dx_set_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->last_frame); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->golden_frame); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->alt_ref_frame); + + else + return -1; + + return 0; +} + +//For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us. +#if HAVE_ARMV7 +extern void vp8_push_neon(INT64 *store); +extern void vp8_pop_neon(INT64 *store); +static INT64 dx_store_reg[8]; +#endif +int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsigned char *source, INT64 time_stamp) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + int retcode = 0; + + struct vpx_usec_timer timer; + +// if(pbi->ready_for_new_data == 0) +// return -1; + + if (ptr == 0) + { + return -1; + } + + pbi->common.error.error_code = VPX_CODEC_OK; + + if (setjmp(pbi->common.error.jmp)) + { + pbi->common.error.setjmp = 0; + return -1; + } + + pbi->common.error.setjmp = 1; + +#if HAVE_ARMV7 + vp8_push_neon(dx_store_reg); +#endif + + vpx_usec_timer_start(&timer); + + //cm->current_video_frame++; + pbi->Source = source; + pbi->source_sz = size; + + retcode = vp8_decode_frame(pbi); + + if (retcode < 0) + { +#if HAVE_ARMV7 + vp8_pop_neon(dx_store_reg); +#endif + pbi->common.error.error_code = VPX_CODEC_ERROR; + pbi->common.error.setjmp = 0; + return retcode; + } + + // Update the GF useage maps. + vp8_update_gf_useage_maps(cm, &pbi->mb); + + if (pbi->b_multithreaded_lf && pbi->common.filter_level != 0) + vp8_stop_lfthread(pbi); + + if (cm->refresh_last_frame) + { + vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); + + cm->frame_to_show = &cm->last_frame; + } + else + { + cm->frame_to_show = &cm->new_frame; + } + + if (!pbi->b_multithreaded_lf) + { + struct vpx_usec_timer lpftimer; + vpx_usec_timer_start(&lpftimer); + // Apply the loop filter if appropriate. + + if (cm->filter_level > 0) + { + vp8_loop_filter_frame(cm, &pbi->mb, cm->filter_level); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + } + + vpx_usec_timer_mark(&lpftimer); + pbi->time_loop_filtering += vpx_usec_timer_elapsed(&lpftimer); + } + + vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); + +#if 0 + // DEBUG code + //vp8_recon_write_yuv_frame("recon.yuv", cm->frame_to_show); + if (cm->current_video_frame <= 5) + write_dx_frame_to_file(cm->frame_to_show, cm->current_video_frame); +#endif + + // If any buffer copy / swaping is signalled it should be done here. + if (cm->copy_buffer_to_arf) + { + if (cm->copy_buffer_to_arf == 1) + { + if (cm->refresh_last_frame) + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->alt_ref_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->alt_ref_frame); + } + else if (cm->copy_buffer_to_arf == 2) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, &cm->alt_ref_frame); + } + + if (cm->copy_buffer_to_gf) + { + if (cm->copy_buffer_to_gf == 1) + { + if (cm->refresh_last_frame) + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->golden_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); + } + else if (cm->copy_buffer_to_gf == 2) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, &cm->golden_frame); + } + + // Should the golden or alternate reference frame be refreshed? + if (cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + { + if (cm->refresh_golden_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); + + if (cm->refresh_alt_ref_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); + + //vpx_log("Decoder: recovery frame received \n"); + + // Update data structures that monitors GF useage + vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cm->gf_active_count = cm->mb_rows * cm->mb_cols; + } + + vp8_clear_system_state(); + + vpx_usec_timer_mark(&timer); + pbi->decode_microseconds = vpx_usec_timer_elapsed(&timer); + + pbi->time_decoding += pbi->decode_microseconds; + +// vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame); + + if (cm->show_frame) + cm->current_video_frame++; + + pbi->ready_for_new_data = 0; + pbi->last_time_stamp = time_stamp; + +#if 0 + { + int i; + INT64 earliest_time = pbi->dr[0].time_stamp; + INT64 latest_time = pbi->dr[0].time_stamp; + INT64 time_diff = 0; + int bytes = 0; + + pbi->dr[pbi->common.current_video_frame&0xf].size = pbi->bc.pos + pbi->bc2.pos + 4;; + pbi->dr[pbi->common.current_video_frame&0xf].time_stamp = time_stamp; + + for (i = 0; i < 16; i++) + { + + bytes += pbi->dr[i].size; + + if (pbi->dr[i].time_stamp < earliest_time) + earliest_time = pbi->dr[i].time_stamp; + + if (pbi->dr[i].time_stamp > latest_time) + latest_time = pbi->dr[i].time_stamp; + } + + time_diff = latest_time - earliest_time; + + if (time_diff > 0) + { + pbi->common.bitrate = 80000.00 * bytes / time_diff ; + pbi->common.framerate = 160000000.00 / time_diff ; + } + + } +#endif + +#if HAVE_ARMV7 + vp8_pop_neon(dx_store_reg); +#endif + pbi->common.error.setjmp = 0; + return retcode; +} +int vp8dx_get_raw_frame(VP8D_PTR ptr, YV12_BUFFER_CONFIG *sd, INT64 *time_stamp, INT64 *time_end_stamp, int deblock_level, int noise_level, int flags) +{ + int ret = -1; + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + + if (pbi->ready_for_new_data == 1) + return ret; + + // ie no raw frame to show!!! + if (pbi->common.show_frame == 0) + return ret; + + pbi->ready_for_new_data = 1; + *time_stamp = pbi->last_time_stamp; + *time_end_stamp = 0; + + sd->clrtype = pbi->common.clr_type; +#if CONFIG_POSTPROC + ret = vp8_post_proc_frame(&pbi->common, sd, deblock_level, noise_level, flags); +#else + + if (pbi->common.frame_to_show) + { + *sd = *pbi->common.frame_to_show; + sd->y_width = pbi->common.Width; + sd->y_height = pbi->common.Height; + sd->uv_height = pbi->common.Height / 2; + ret = 0; + } + else + { + ret = -1; + } + +#endif //!CONFIG_POSTPROC + vp8_clear_system_state(); + return ret; +}
diff --git a/vp8/decoder/onyxd_if_sjl.c b/vp8/decoder/onyxd_if_sjl.c new file mode 100644 index 0000000..363ad5d --- /dev/null +++ b/vp8/decoder/onyxd_if_sjl.c
@@ -0,0 +1,398 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxc_int.h" +#include "postproc.h" +#include "onyxd.h" +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "alloccommon.h" +#include "vpx_scale/yv12extend.h" +#include "loopfilter.h" +#include "swapyv12buffer.h" +#include "g_common.h" +#include "threading.h" +#include "decoderthreading.h" +#include <stdio.h> +#include "segmentation_common.h" +#include "quant_common.h" +#include "vpx_scale/vpxscale.h" +#include "systemdependent.h" +#include "vpx_ports/vpx_timer.h" + + +#ifndef VPX_NO_GLOBALS +static int init_ct = 0; +#else +# include "vpx_global_handling.h" +# define init_ct ((int)vpxglobalm(onyxd,init_ct)) +#endif + +extern void vp8_init_loop_filter(VP8_COMMON *cm); + +extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); +extern void init_detokenizer(VP8D_COMP *dx); + +// DEBUG code +void vp8_recon_write_yuv_frame(unsigned char *name, YV12_BUFFER_CONFIG *s) +{ + FILE *yuv_file = fopen((char *)name, "ab"); + unsigned char *src = s->y_buffer; + int h = s->y_height; + + do + { + fwrite(src, s->y_width, 1, yuv_file); + src += s->y_stride; + } + while (--h); + + src = s->u_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + src = s->v_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + fclose(yuv_file); +} + +void vp8dx_initialize() +{ + if (!init_ct++) + { + vp8_initialize_common(); + vp8_scale_machine_specific_config(); + } +} + +void vp8dx_shutdown() +{ + if (!--init_ct) + { + vp8_shutdown_common(); + } +} + + +VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) +{ + VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); + + if (!pbi) + return NULL; + + vpx_memset(pbi, 0, sizeof(VP8D_COMP)); + + vp8dx_initialize(); + + vp8_create_common(&pbi->common); + vp8_dmachine_specific_config(pbi); + + pbi->common.current_video_frame = 0; + pbi->ready_for_new_data = 1; + + pbi->CPUFreq = 0; //vp8_get_processor_freq(); + pbi->max_threads = oxcf->max_threads; + vp8_decoder_create_threads(pbi); + + //vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid + // unnecessary calling of vp8cx_init_de_quantizer() for every frame. + vp8cx_init_de_quantizer(pbi); + + { + VP8_COMMON *cm = &pbi->common; + + vp8_init_loop_filter(cm); + cm->last_frame_type = KEY_FRAME; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + } + + init_detokenizer(pbi); + + return (VP8D_PTR) pbi; +} +void vp8dx_remove_decompressor(VP8D_PTR ptr) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + + if (!pbi) + return; + + vp8_decoder_remove_threads(pbi); + vp8_remove_common(&pbi->common); + vpx_free(pbi); + vp8dx_shutdown(); + +} + +void vp8dx_set_setting(VP8D_PTR comp, VP8D_SETTING oxst, int x) +{ + VP8D_COMP *pbi = (VP8D_COMP *) comp; + + (void) pbi; + (void) x; + + switch (oxst) + { + case VP8D_OK: + break; + } +} + +int vp8dx_get_setting(VP8D_PTR comp, VP8D_SETTING oxst) +{ + VP8D_COMP *pbi = (VP8D_COMP *) comp; + + (void) pbi; + + switch (oxst) + { + case VP8D_OK: + break; + } + + return -1; +} + +int vp8dx_get_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(&cm->last_frame, sd); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, sd); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, sd); + + else + return -1; + + return 0; +} +int vp8dx_set_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->last_frame); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->golden_frame); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->alt_ref_frame); + + else + return -1; + + return 0; +} +int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, char *source, INT64 time_stamp) +{ + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + VP8_COMMON *cm = &pbi->common; + int retcode = 0; + + struct vpx_usec_timer timer; + (void) size; + +// if(pbi->ready_for_new_data == 0) +// return -1; + + vpx_usec_timer_start(&timer); + + if (ptr == 0) + { + return -1; + } + + //cm->current_video_frame++; + pbi->Source = source; + + retcode = vp8_decode_frame(pbi); + + if (retcode < 0) + return retcode; + + // Update the GF useage maps. + vp8_update_gf_useage_maps(cm, &pbi->mb); + + if (pbi->b_multithreaded) + vp8_stop_lfthread(pbi); + + if (cm->refresh_last_frame) + { + vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); + + cm->frame_to_show = &cm->last_frame; + } + else + { + cm->frame_to_show = &cm->new_frame; + } + + if (!pbi->b_multithreaded) + { + struct vpx_usec_timer lpftimer; + vpx_usec_timer_start(&lpftimer); + // Apply the loop filter if appropriate. + + if (cm->filter_level > 0) + { + vp8_loop_filter_frame(cm, &pbi->mb, cm->filter_level); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + } + + vpx_usec_timer_mark(&lpftimer); + pbi->time_loop_filtering += vpx_usec_timer_elapsed(&lpftimer); + } + + vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); + +#if 0 + // DEBUG code + //vp8_recon_write_yuv_frame("recon.yuv", cm->frame_to_show); + if (cm->current_video_frame <= 5) + write_dx_frame_to_file(cm->frame_to_show, cm->current_video_frame); +#endif + + // If any buffer copy / swaping is signalled it should be done here. + if (cm->copy_buffer_to_arf) + { + if (cm->copy_buffer_to_arf == 1) + { + if (cm->refresh_last_frame) + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->alt_ref_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->alt_ref_frame); + } + else if (cm->copy_buffer_to_arf == 2) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, &cm->alt_ref_frame); + } + + if (cm->copy_buffer_to_gf) + { + if (cm->copy_buffer_to_gf == 1) + { + if (cm->refresh_last_frame) + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->golden_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); + } + else if (cm->copy_buffer_to_gf == 2) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, &cm->golden_frame); + } + + // Should the golden or alternate reference frame be refreshed? + if (cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + { + if (cm->refresh_golden_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); + + if (cm->refresh_alt_ref_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); + + //vpx_log("Decoder: recovery frame received \n"); + + // Update data structures that monitors GF useage + vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cm->gf_active_count = cm->mb_rows * cm->mb_cols; + } + + vp8_clear_system_state(); + + vpx_usec_timer_mark(&timer); + pbi->decode_microseconds = vpx_usec_timer_elapsed(&timer); + + pbi->time_decoding += pbi->decode_microseconds; + +// vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame); + + cm->current_video_frame++; + pbi->ready_for_new_data = 0; + pbi->last_time_stamp = time_stamp; + + { + int i; + INT64 earliest_time = pbi->dr[0].time_stamp; + INT64 latest_time = pbi->dr[0].time_stamp; + INT64 time_diff = 0; + int bytes = 0; + + pbi->dr[pbi->common.current_video_frame&0xf].size = pbi->bc.pos + pbi->bc2.pos + 4;; + pbi->dr[pbi->common.current_video_frame&0xf].time_stamp = time_stamp; + + for (i = 0; i < 16; i++) + { + + bytes += pbi->dr[i].size; + + if (pbi->dr[i].time_stamp < earliest_time) + earliest_time = pbi->dr[i].time_stamp; + + if (pbi->dr[i].time_stamp > latest_time) + latest_time = pbi->dr[i].time_stamp; + } + + time_diff = latest_time - earliest_time; + + if (time_diff > 0) + { + pbi->common.bitrate = 80000.00 * bytes / time_diff ; + pbi->common.framerate = 160000000.00 / time_diff ; + } + + } + return retcode; +} +int vp8dx_get_raw_frame(VP8D_PTR ptr, YV12_BUFFER_CONFIG *sd, INT64 *time_stamp, INT64 *time_end_stamp, int deblock_level, int noise_level, int flags) +{ + int ret = -1; + VP8D_COMP *pbi = (VP8D_COMP *) ptr; + + if (pbi->ready_for_new_data == 1) + return ret; + + // ie no raw frame to show!!! + if (pbi->common.show_frame == 0) + return ret; + + pbi->ready_for_new_data = 1; + *time_stamp = pbi->last_time_stamp; + *time_end_stamp = 0; + + sd->clrtype = pbi->common.clr_type; + ret = vp8_post_proc_frame(&pbi->common, sd, deblock_level, noise_level, flags); + vp8_clear_system_state(); + return ret; +}
diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h new file mode 100644 index 0000000..fa4fa48 --- /dev/null +++ b/vp8/decoder/onyxd_int.h
@@ -0,0 +1,149 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_VP8D_INT_H +#define __INC_VP8D_INT_H +#include "vpx_ports/config.h" +#include "onyxd.h" +#include "treereader.h" +#include "onyxc_int.h" +#include "threading.h" +#include "dequantize.h" + +typedef struct +{ + int ithread; + void *ptr1; + void *ptr2; +} DECODETHREAD_DATA; + +typedef struct +{ + MACROBLOCKD mbd; + int mb_row; + int current_mb_col; + short *coef_ptr; +} MB_ROW_DEC; + +typedef struct +{ + INT64 time_stamp; + int size; +} DATARATE; + +typedef struct +{ + INT16 min_val; + INT16 Length; + UINT8 Probs[12]; +} TOKENEXTRABITS; + +typedef struct +{ + int *scan; + UINT8 *ptr_onyxblock2context_leftabove; + vp8_tree_index *vp8_coef_tree_ptr; //onyx_coef_tree_ptr; ??? + TOKENEXTRABITS *teb_base_ptr; + unsigned char *norm_ptr; +// UINT16 *ptr_onyx_coef_bands_x; + UINT8 *ptr_onyx_coef_bands_x; + + ENTROPY_CONTEXT **A; + ENTROPY_CONTEXT(*L)[4]; + + INT16 *qcoeff_start_ptr; + BOOL_DECODER *current_bc; + + UINT8 *coef_probs[4]; + + UINT8 eob[25]; + +} DETOK; + +typedef struct VP8Decompressor +{ + DECLARE_ALIGNED(16, MACROBLOCKD, mb); + + DECLARE_ALIGNED(16, VP8_COMMON, common); + + vp8_reader bc, bc2; + + VP8D_CONFIG oxcf; + + + const unsigned char *Source; + unsigned int source_sz; + + + unsigned int CPUFreq; + unsigned int decode_microseconds; + unsigned int time_decoding; + unsigned int time_loop_filtering; + + volatile int b_multithreaded_rd; + volatile int b_multithreaded_lf; + int max_threads; + int last_mb_row_decoded; + int current_mb_col_main; + int decoding_thread_count; + int allocated_decoding_thread_count; + + // variable for threading + DECLARE_ALIGNED(16, MACROBLOCKD, lpfmb); +#if CONFIG_MULTITHREAD + pthread_t h_thread_lpf; // thread for postprocessing + sem_t h_event_lpf; // Event for post_proc completed + sem_t h_event_start_lpf; +#endif + MB_ROW_DEC *mb_row_di; + DECODETHREAD_DATA *de_thread_data; +#if CONFIG_MULTITHREAD + pthread_t *h_decoding_thread; + sem_t *h_event_mbrdecoding; + sem_t h_event_main; + // end of threading data +#endif + vp8_reader *mbc; + INT64 last_time_stamp; + int ready_for_new_data; + + DATARATE dr[16]; + + DETOK detoken; + +#if CONFIG_RUNTIME_CPU_DETECT + vp8_dequant_rtcd_vtable_t dequant; + struct vp8_dboolhuff_rtcd_vtable dboolhuff; +#endif + +} VP8D_COMP; + +int vp8_decode_frame(VP8D_COMP *cpi); +void vp8_dmachine_specific_config(VP8D_COMP *pbi); + + +#if CONFIG_DEBUG +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval" at %s:%d", \ + __FILE__,__LINE__);\ + } while(0) +#else +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval);\ + } while(0) +#endif + +#endif
diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c new file mode 100644 index 0000000..e35d175 --- /dev/null +++ b/vp8/decoder/threading.c
@@ -0,0 +1,596 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef WIN32 +# include <unistd.h> +#endif +#include "onyxd_int.h" +#include "vpx_mem/vpx_mem.h" +#include "threading.h" + +#include "loopfilter.h" +#include "extend.h" +#include "vpx_ports/vpx_timer.h" + +extern void vp8_decode_mb_row(VP8D_COMP *pbi, + VP8_COMMON *pc, + int mb_row, + MACROBLOCKD *xd); + +extern void vp8_build_uvmvs(MACROBLOCKD *x, int fullpixel); +extern void vp8_decode_macroblock(VP8D_COMP *pbi, MACROBLOCKD *xd); + +void vp8_setup_decoding_thread_data(VP8D_COMP *pbi, MACROBLOCKD *xd, MB_ROW_DEC *mbrd, int count) +{ + + + +#if CONFIG_MULTITHREAD + VP8_COMMON *const pc = & pbi->common; + int i, j; + + for (i = 0; i < count; i++) + { + MACROBLOCKD *mbd = &mbrd[i].mbd; +#if CONFIG_RUNTIME_CPU_DETECT + mbd->rtcd = xd->rtcd; +#endif + + + mbd->subpixel_predict = xd->subpixel_predict; + mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; + mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; + mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; + mbd->gf_active_ptr = xd->gf_active_ptr; + + mbd->mode_info = pc->mi - 1; + mbd->mode_info_context = pc->mi + pc->mode_info_stride * (i + 1); + mbd->mode_info_stride = pc->mode_info_stride; + + mbd->frame_type = pc->frame_type; + mbd->frames_since_golden = pc->frames_since_golden; + mbd->frames_till_alt_ref_frame = pc->frames_till_alt_ref_frame; + + mbd->pre = pc->last_frame; + mbd->dst = pc->new_frame; + + + + + vp8_setup_block_dptrs(mbd); + vp8_build_block_doffsets(mbd); + mbd->segmentation_enabled = xd->segmentation_enabled; + mbd->mb_segement_abs_delta = xd->mb_segement_abs_delta; + vpx_memcpy(mbd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); + + mbd->mbmi.mode = DC_PRED; + mbd->mbmi.uv_mode = DC_PRED; + + mbd->current_bc = &pbi->bc2; + + for (j = 0; j < 25; j++) + { + mbd->block[j].dequant = xd->block[j].dequant; + } + } + +#else + (void) pbi; + (void) xd; + (void) mbrd; + (void) count; +#endif +} + + +THREAD_FUNCTION vp8_thread_decoding_proc(void *p_data) +{ +#if CONFIG_MULTITHREAD + int ithread = ((DECODETHREAD_DATA *)p_data)->ithread; + VP8D_COMP *pbi = (VP8D_COMP *)(((DECODETHREAD_DATA *)p_data)->ptr1); + MB_ROW_DEC *mbrd = (MB_ROW_DEC *)(((DECODETHREAD_DATA *)p_data)->ptr2); + ENTROPY_CONTEXT mb_row_left_context[4][4]; + + while (1) + { + if (pbi->b_multithreaded_rd == 0) + break; + + //if(WaitForSingleObject(pbi->h_event_mbrdecoding[ithread], INFINITE) == WAIT_OBJECT_0) + if (sem_wait(&pbi->h_event_mbrdecoding[ithread]) == 0) + { + if (pbi->b_multithreaded_rd == 0) + break; + else + { + VP8_COMMON *pc = &pbi->common; + int mb_row = mbrd->mb_row; + MACROBLOCKD *xd = &mbrd->mbd; + + //printf("ithread:%d mb_row %d\n", ithread, mb_row); + int i; + int recon_yoffset, recon_uvoffset; + int mb_col; + int recon_y_stride = pc->last_frame.y_stride; + int recon_uv_stride = pc->last_frame.uv_stride; + + volatile int *last_row_current_mb_col; + + if (ithread > 0) + last_row_current_mb_col = &pbi->mb_row_di[ithread-1].current_mb_col; + else + last_row_current_mb_col = &pbi->current_mb_col_main; + + recon_yoffset = mb_row * recon_y_stride * 16; + recon_uvoffset = mb_row * recon_uv_stride * 8; + // reset above block coeffs + + xd->above_context[Y1CONTEXT] = pc->above_context[Y1CONTEXT]; + xd->above_context[UCONTEXT ] = pc->above_context[UCONTEXT]; + xd->above_context[VCONTEXT ] = pc->above_context[VCONTEXT]; + xd->above_context[Y2CONTEXT] = pc->above_context[Y2CONTEXT]; + xd->left_context = mb_row_left_context; + vpx_memset(mb_row_left_context, 0, sizeof(mb_row_left_context)); + xd->up_available = (mb_row != 0); + + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + + for (mb_col = 0; mb_col < pc->mb_cols; mb_col++) + { + + while (mb_col > (*last_row_current_mb_col - 1) && *last_row_current_mb_col != pc->mb_cols - 1) + { + x86_pause_hint(); + thread_sleep(0); + } + + // Take a copy of the mode and Mv information for this macroblock into the xd->mbmi + vpx_memcpy(&xd->mbmi, &xd->mode_info_context->mbmi, 32); //sizeof(MB_MODE_INFO) ); + + if (xd->mbmi.mode == SPLITMV || xd->mbmi.mode == B_PRED) + { + for (i = 0; i < 16; i++) + { + BLOCKD *d = &xd->block[i]; + vpx_memcpy(&d->bmi, &xd->mode_info_context->bmi[i], sizeof(B_MODE_INFO)); + } + } + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + + xd->dst.y_buffer = pc->new_frame.y_buffer + recon_yoffset; + xd->dst.u_buffer = pc->new_frame.u_buffer + recon_uvoffset; + xd->dst.v_buffer = pc->new_frame.v_buffer + recon_uvoffset; + + xd->left_available = (mb_col != 0); + + // Select the appropriate reference frame for this MB + if (xd->mbmi.ref_frame == LAST_FRAME) + { + xd->pre.y_buffer = pc->last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->last_frame.v_buffer + recon_uvoffset; + } + else if (xd->mbmi.ref_frame == GOLDEN_FRAME) + { + // Golden frame reconstruction buffer + xd->pre.y_buffer = pc->golden_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->golden_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->golden_frame.v_buffer + recon_uvoffset; + } + else + { + // Alternate reference frame reconstruction buffer + xd->pre.y_buffer = pc->alt_ref_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = pc->alt_ref_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = pc->alt_ref_frame.v_buffer + recon_uvoffset; + } + + vp8_build_uvmvs(xd, pc->full_pixel); + + vp8dx_bool_decoder_fill(xd->current_bc); + vp8_decode_macroblock(pbi, xd); + + + recon_yoffset += 16; + recon_uvoffset += 8; + + ++xd->mode_info_context; /* next mb */ + + xd->gf_active_ptr++; // GF useage flag for next MB + + xd->above_context[Y1CONTEXT] += 4; + xd->above_context[UCONTEXT ] += 2; + xd->above_context[VCONTEXT ] += 2; + xd->above_context[Y2CONTEXT] ++; + pbi->mb_row_di[ithread].current_mb_col = mb_col; + + } + + // adjust to the next row of mbs + vp8_extend_mb_row( + &pc->new_frame, + xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8 + ); + + ++xd->mode_info_context; /* skip prediction column */ + + // since we have multithread + xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count; + + //memcpy(&pbi->lpfmb, &pbi->mb, sizeof(pbi->mb)); + if ((mb_row & 1) == 1) + { + pbi->last_mb_row_decoded = mb_row; + //printf("S%d", pbi->last_mb_row_decoded); + } + + if (ithread == (pbi->decoding_thread_count - 1) || mb_row == pc->mb_rows - 1) + { + //SetEvent(pbi->h_event_main); + sem_post(&pbi->h_event_main); + + } + } + } + } + +#else + (void) p_data; +#endif + + return 0 ; +} + +THREAD_FUNCTION vp8_thread_loop_filter(void *p_data) +{ +#if CONFIG_MULTITHREAD + VP8D_COMP *pbi = (VP8D_COMP *)p_data; + + while (1) + { + if (pbi->b_multithreaded_lf == 0) + break; + + //printf("before waiting for start_lpf\n"); + + //if(WaitForSingleObject(pbi->h_event_start_lpf, INFINITE) == WAIT_OBJECT_0) + if (sem_wait(&pbi->h_event_start_lpf) == 0) + { + if (pbi->b_multithreaded_lf == 0) // we're shutting down + break; + else + { + + VP8_COMMON *cm = &pbi->common; + MACROBLOCKD *mbd = &pbi->lpfmb; + int default_filt_lvl = pbi->common.filter_level; + + YV12_BUFFER_CONFIG *post = &cm->new_frame; + loop_filter_info *lfi = cm->lf_info; + + int mb_row; + int mb_col; + + + int baseline_filter_level[MAX_MB_SEGMENTS]; + int filter_level; + int alt_flt_enabled = mbd->segmentation_enabled; + + int i; + unsigned char *y_ptr, *u_ptr, *v_ptr; + + volatile int *last_mb_row_decoded = &pbi->last_mb_row_decoded; + + //MODE_INFO * this_mb_mode_info = cm->mi; + mbd->mode_info_context = cm->mi; // Point at base of Mb MODE_INFO list + + // Note the baseline filter values for each segment + if (alt_flt_enabled) + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + { + if (mbd->mb_segement_abs_delta == SEGMENT_ABSDATA) + baseline_filter_level[i] = mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + else + { + baseline_filter_level[i] = default_filt_lvl + mbd->segment_feature_data[MB_LVL_ALT_LF][i]; + baseline_filter_level[i] = (baseline_filter_level[i] >= 0) ? ((baseline_filter_level[i] <= MAX_LOOP_FILTER) ? baseline_filter_level[i] : MAX_LOOP_FILTER) : 0; // Clamp to valid range + } + } + } + else + { + for (i = 0; i < MAX_MB_SEGMENTS; i++) + baseline_filter_level[i] = default_filt_lvl; + } + + // Initialize the loop filter for this frame. + vp8_init_loop_filter(cm); + + // Set up the buffer pointers + y_ptr = post->y_buffer; + u_ptr = post->u_buffer; + v_ptr = post->v_buffer; + + // vp8_filter each macro block + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + + while (mb_row >= *last_mb_row_decoded) + { + x86_pause_hint(); + thread_sleep(0); + } + + //printf("R%d", mb_row); + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int Segment = (alt_flt_enabled) ? mbd->mode_info_context->mbmi.segment_id : 0; + + filter_level = baseline_filter_level[Segment]; + + // Apply any context driven MB level adjustment + vp8_adjust_mb_lf_value(mbd, &filter_level); + + if (filter_level) + { + if (mb_col > 0) + cm->lf_mbv(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bv(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + // don't apply across umv border + if (mb_row > 0) + cm->lf_mbh(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + + if (mbd->mode_info_context->mbmi.dc_diff > 0) + cm->lf_bh(y_ptr, u_ptr, v_ptr, post->y_stride, post->uv_stride, &lfi[filter_level], cm->simpler_lpf); + } + + y_ptr += 16; + u_ptr += 8; + v_ptr += 8; + + mbd->mode_info_context++; // step to next MB + + } + + y_ptr += post->y_stride * 16 - post->y_width; + u_ptr += post->uv_stride * 8 - post->uv_width; + v_ptr += post->uv_stride * 8 - post->uv_width; + + mbd->mode_info_context++; // Skip border mb + } + + //printf("R%d\n", mb_row); + // When done, signal main thread that ME is finished + //SetEvent(pbi->h_event_lpf); + sem_post(&pbi->h_event_lpf); + } + + } + } + +#else + (void) p_data; +#endif + return 0; +} + +void vp8_decoder_create_threads(VP8D_COMP *pbi) +{ +#if CONFIG_MULTITHREAD + int core_count = 0; + int ithread; + + pbi->b_multithreaded_rd = 0; + pbi->b_multithreaded_lf = 0; + pbi->allocated_decoding_thread_count = 0; + core_count = (pbi->max_threads > 16) ? 16 : pbi->max_threads; //vp8_get_proc_core_count(); + if (core_count > 1) + { + sem_init(&pbi->h_event_lpf, 0, 0); + sem_init(&pbi->h_event_start_lpf, 0, 0); + pbi->b_multithreaded_lf = 1; + pthread_create(&pbi->h_thread_lpf, 0, vp8_thread_loop_filter, (pbi)); + } + + if (core_count > 1) + { + pbi->b_multithreaded_rd = 1; + pbi->decoding_thread_count = core_count - 1; + + CHECK_MEM_ERROR(pbi->h_decoding_thread, vpx_malloc(sizeof(pthread_t) * pbi->decoding_thread_count)); + CHECK_MEM_ERROR(pbi->h_event_mbrdecoding, vpx_malloc(sizeof(sem_t) * pbi->decoding_thread_count)); + CHECK_MEM_ERROR(pbi->mb_row_di, vpx_memalign(32, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count)); + vpx_memset(pbi->mb_row_di, 0, sizeof(MB_ROW_DEC) * pbi->decoding_thread_count); + CHECK_MEM_ERROR(pbi->de_thread_data, vpx_malloc(sizeof(DECODETHREAD_DATA) * pbi->decoding_thread_count)); + + for (ithread = 0; ithread < pbi->decoding_thread_count; ithread++) + { + sem_init(&pbi->h_event_mbrdecoding[ithread], 0, 0); + + pbi->de_thread_data[ithread].ithread = ithread; + pbi->de_thread_data[ithread].ptr1 = (void *)pbi; + pbi->de_thread_data[ithread].ptr2 = (void *) &pbi->mb_row_di[ithread]; + + pthread_create(&pbi->h_decoding_thread[ithread], 0, vp8_thread_decoding_proc, (&pbi->de_thread_data[ithread])); + + } + + sem_init(&pbi->h_event_main, 0, 0); + pbi->allocated_decoding_thread_count = pbi->decoding_thread_count; + } + +#else + (void) pbi; +#endif +} + +void vp8_decoder_remove_threads(VP8D_COMP *pbi) +{ +#if CONFIG_MULTITHREAD + + if (pbi->b_multithreaded_lf) + { + pbi->b_multithreaded_lf = 0; + sem_post(&pbi->h_event_start_lpf); + pthread_join(pbi->h_thread_lpf, 0); + sem_destroy(&pbi->h_event_start_lpf); + } + + //shutdown MB Decoding thread; + if (pbi->b_multithreaded_rd) + { + pbi->b_multithreaded_rd = 0; + // allow all threads to exit + { + int i; + + for (i = 0; i < pbi->allocated_decoding_thread_count; i++) + { + + sem_post(&pbi->h_event_mbrdecoding[i]); + pthread_join(pbi->h_decoding_thread[i], NULL); + } + } + { + + int i; + for (i = 0; i < pbi->allocated_decoding_thread_count; i++) + { + sem_destroy(&pbi->h_event_mbrdecoding[i]); + } + + + } + + sem_destroy(&pbi->h_event_main); + + if (pbi->h_decoding_thread) + { + vpx_free(pbi->h_decoding_thread); + pbi->h_decoding_thread = NULL; + } + + if (pbi->h_event_mbrdecoding) + { + vpx_free(pbi->h_event_mbrdecoding); + pbi->h_event_mbrdecoding = NULL; + } + + if (pbi->mb_row_di) + { + vpx_free(pbi->mb_row_di); + pbi->mb_row_di = NULL ; + } + + if (pbi->de_thread_data) + { + vpx_free(pbi->de_thread_data); + pbi->de_thread_data = NULL; + } + } + +#else + (void) pbi; +#endif +} + + +void vp8_start_lfthread(VP8D_COMP *pbi) +{ +#if CONFIG_MULTITHREAD + memcpy(&pbi->lpfmb, &pbi->mb, sizeof(pbi->mb)); + pbi->last_mb_row_decoded = 0; + sem_post(&pbi->h_event_start_lpf); +#else + (void) pbi; +#endif +} + +void vp8_stop_lfthread(VP8D_COMP *pbi) +{ +#if CONFIG_MULTITHREAD + struct vpx_usec_timer timer; + + vpx_usec_timer_start(&timer); + + sem_wait(&pbi->h_event_lpf); + + vpx_usec_timer_mark(&timer); + pbi->time_loop_filtering += vpx_usec_timer_elapsed(&timer); +#else + (void) pbi; +#endif +} + + +void vp8_mtdecode_mb_rows(VP8D_COMP *pbi, + MACROBLOCKD *xd) +{ +#if CONFIG_MULTITHREAD + int mb_row; + VP8_COMMON *pc = &pbi->common; + + int ibc = 0; + int num_part = 1 << pbi->common.multi_token_partition; + + vp8_setup_decoding_thread_data(pbi, xd, pbi->mb_row_di, pbi->decoding_thread_count); + + for (mb_row = 0; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1)) + { + int i; + pbi->current_mb_col_main = -1; + + xd->current_bc = &pbi->mbc[ibc]; + ibc++ ; + + if (ibc == num_part) + ibc = 0; + + for (i = 0; i < pbi->decoding_thread_count; i++) + { + if ((mb_row + i + 1) >= pc->mb_rows) + break; + + pbi->mb_row_di[i].mb_row = mb_row + i + 1; + pbi->mb_row_di[i].mbd.current_bc = &pbi->mbc[ibc]; + ibc++; + + if (ibc == num_part) + ibc = 0; + + pbi->mb_row_di[i].current_mb_col = -1; + sem_post(&pbi->h_event_mbrdecoding[i]); + } + + vp8_decode_mb_row(pbi, pc, mb_row, xd); + + xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count; + + if (mb_row < pc->mb_rows - 1) + { + sem_wait(&pbi->h_event_main); + } + } + + pbi->last_mb_row_decoded = mb_row; +#else + (void) pbi; + (void) xd; +#endif +}
diff --git a/vp8/decoder/treereader.h b/vp8/decoder/treereader.h new file mode 100644 index 0000000..eb10e24 --- /dev/null +++ b/vp8/decoder/treereader.h
@@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef tree_reader_h +#define tree_reader_h 1 + +#include "treecoder.h" + +#include "dboolhuff.h" + +typedef BOOL_DECODER vp8_reader; + +#define vp8_read vp8dx_decode_bool +#define vp8_read_literal vp8_decode_value +#define vp8_read_bit( R) vp8_read( R, vp8_prob_half) + + +/* Intent of tree data structure is to make decoding trivial. */ + +static int vp8_treed_read( + vp8_reader *const r, /* !!! must return a 0 or 1 !!! */ + vp8_tree t, + const vp8_prob *const p +) +{ + register vp8_tree_index i = 0; + + while ((i = t[ i + vp8_read(r, p[i>>1])]) > 0) ; + + return -i; +} + + +/* Variant reads a binary number given distributions on each bit. + Note that tree is arbitrary; probability of decoding a zero + may or may not depend on previously decoded bits. */ + +static int vp8_treed_read_num( + vp8_reader *const r, /* !!! must return a 0 or 1 !!! */ + vp8_tree t, + const vp8_prob *const p +) +{ + vp8_tree_index i = 0; + int v = 0, b; + + do + { + b = vp8_read(r, p[i>>1]); + v = (v << 1) + b; + } + while ((i = t[i+b]) > 0); + + return v; +} +#endif /* tree_reader_h */
diff --git a/vp8/decoder/x86/dequantize_mmx.asm b/vp8/decoder/x86/dequantize_mmx.asm new file mode 100644 index 0000000..02be487 --- /dev/null +++ b/vp8/decoder/x86/dequantize_mmx.asm
@@ -0,0 +1,410 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;void vp8_dequantize_b_impl_mmx(short *sq, short *dq, short *q) +global sym(vp8_dequantize_b_impl_mmx) +sym(vp8_dequantize_b_impl_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;sq + mov rdi, arg(1) ;dq + mov rax, arg(2) ;q + + movq mm1, [rsi] + pmullw mm1, [rax+0] ; mm4 *= kernel 0 modifiers. + movq [rdi], mm1 + + movq mm1, [rsi+8] + pmullw mm1, [rax+8] ; mm4 *= kernel 0 modifiers. + movq [rdi+8], mm1 + + movq mm1, [rsi+16] + pmullw mm1, [rax+16] ; mm4 *= kernel 0 modifiers. + movq [rdi+16], mm1 + + movq mm1, [rsi+24] + pmullw mm1, [rax+24] ; mm4 *= kernel 0 modifiers. + movq [rdi+24], mm1 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;void dequant_idct_mmx(short *input, short *dq, short *output, int pitch) +global sym(vp8_dequant_idct_mmx) +sym(vp8_dequant_idct_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(0) ;input + mov rdx, arg(1) ;dq + + + movq mm0, [rax ] + pmullw mm0, [rdx] + + movq mm1, [rax +8] + pmullw mm1, [rdx +8] + + movq mm2, [rax+16] + pmullw mm2, [rdx+16] + + movq mm3, [rax+24] + pmullw mm3, [rdx+24] + + mov rdx, arg(2) ;output + pxor mm7, mm7 + + + movq [rax], mm7 + movq [rax+8], mm7 + + movq [rax+16],mm7 + movq [rax+24],mm7 + + + movsxd rax, dword ptr arg(3) ;pitch + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq mm3, mm5 ; 33 23 13 03 + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + paddw mm0, [fours GLOBAL] + + paddw mm2, [fours GLOBAL] + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + psraw mm2, 3 + + psraw mm0, 3 + psraw mm4, 3 + + psraw mm6, 3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq [rdx], mm0 + + movq [rdx+rax], mm1 + movq [rdx+rax*2], mm2 + + add rdx, rax + movq [rdx+rax*2], mm5 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void dequant_dc_idct_mmx(short *input, short *dq, short *output, int pitch, int Dc) +global sym(vp8_dequant_dc_idct_mmx) +sym(vp8_dequant_dc_idct_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rax, arg(0) ;input + mov rdx, arg(1) ;dq + + movsxd rcx, dword ptr arg(4) ;Dc + + movq mm0, [rax ] + pmullw mm0, [rdx] + + movq mm1, [rax +8] + pmullw mm1, [rdx +8] + + movq mm2, [rax+16] + pmullw mm2, [rdx+16] + + movq mm3, [rax+24] + pmullw mm3, [rdx+24] + + mov rdx, arg(2) ;output + pxor mm7, mm7 + + + movq [rax], mm7 + movq [rax+8], mm7 + + movq [rax+16],mm7 + movq [rax+24],mm7 + + pinsrw mm0, rcx, 0 + movsxd rax, dword ptr arg(3) ;pitch + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq mm3, mm5 ; 33 23 13 03 + + psubw mm0, mm2 ; b1= 0-2 + paddw mm2, mm2 ; + + movq mm5, mm1 + paddw mm2, mm0 ; a1 =0+2 + + pmulhw mm5, [x_s1sqr2 GLOBAL]; + paddw mm5, mm1 ; ip1 * sin(pi/8) * sqrt(2) + + movq mm7, mm3 ; + pmulhw mm7, [x_c1sqr2less1 GLOBAL]; + + paddw mm7, mm3 ; ip3 * cos(pi/8) * sqrt(2) + psubw mm7, mm5 ; c1 + + movq mm5, mm1 + movq mm4, mm3 + + pmulhw mm5, [x_c1sqr2less1 GLOBAL] + paddw mm5, mm1 + + pmulhw mm3, [x_s1sqr2 GLOBAL] + paddw mm3, mm4 + + paddw mm3, mm5 ; d1 + paddw mm0, [fours GLOBAL] + + paddw mm2, [fours GLOBAL] + movq mm6, mm2 ; a1 + + movq mm4, mm0 ; b1 + paddw mm2, mm3 ;0 + + paddw mm4, mm7 ;1 + psubw mm0, mm7 ;2 + + psubw mm6, mm3 ;3 + psraw mm2, 3 + + psraw mm0, 3 + psraw mm4, 3 + + psraw mm6, 3 + + movq mm1, mm2 ; 03 02 01 00 + movq mm3, mm4 ; 23 22 21 20 + + punpcklwd mm1, mm0 ; 11 01 10 00 + punpckhwd mm2, mm0 ; 13 03 12 02 + + punpcklwd mm3, mm6 ; 31 21 30 20 + punpckhwd mm4, mm6 ; 33 23 32 22 + + movq mm0, mm1 ; 11 01 10 00 + movq mm5, mm2 ; 13 03 12 02 + + punpckldq mm0, mm3 ; 30 20 10 00 + punpckhdq mm1, mm3 ; 31 21 11 01 + + punpckldq mm2, mm4 ; 32 22 12 02 + punpckhdq mm5, mm4 ; 33 23 13 03 + + movq [rdx], mm0 + + movq [rdx+rax], mm1 + movq [rdx+rax*2], mm2 + + add rdx, rax + movq [rdx+rax*2], mm5 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +align 16 +x_s1sqr2: + times 4 dw 0x8A8C +align 16 +x_c1sqr2less1: + times 4 dw 0x4E7B +align 16 +fours: + times 4 dw 0x0004
diff --git a/vp8/decoder/x86/dequantize_x86.h b/vp8/decoder/x86/dequantize_x86.h new file mode 100644 index 0000000..5def406 --- /dev/null +++ b/vp8/decoder/x86/dequantize_x86.h
@@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DEQUANTIZE_X86_H +#define DEQUANTIZE_X86_H + + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ +#if HAVE_MMX +extern prototype_dequant_block(vp8_dequantize_b_mmx); +extern prototype_dequant_idct(vp8_dequant_idct_mmx); +extern prototype_dequant_idct_dc(vp8_dequant_dc_idct_mmx); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_dequant_block +#define vp8_dequant_block vp8_dequantize_b_mmx + +#undef vp8_dequant_idct +#define vp8_dequant_idct vp8_dequant_idct_mmx + +#undef vp8_dequant_idct_dc +#define vp8_dequant_idct_dc vp8_dequant_dc_idct_mmx + +#endif +#endif + +#endif
diff --git a/vp8/decoder/x86/onyxdxv.c b/vp8/decoder/x86/onyxdxv.c new file mode 100644 index 0000000..75a676a --- /dev/null +++ b/vp8/decoder/x86/onyxdxv.c
@@ -0,0 +1,1079 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : onyxdxv.c +* +* Description : VP80 interface to DXV. +* +***************************************************************************** +*/ +/**************************************************************************** +* Header Files +****************************************************************************/ +#include <math.h> // For Abs() +#include "pragmas.h" + +#include "vpxdxv.h" +#include "vpxdxv_plugin.h" + +#include "onyxd_int.h" +#include "onyx.h" +#include "codec_common_interface.h" +#include "vpx_scale/vpxscale.h" +#include "vpx_mem/vpx_mem.h" +#include "postproc.h" +#include "vpxblit.h" +#include "g_common.h" +#include "vpx_scale/yv12extend.h" + +#include <limits.h> +#include <stdio.h> +#include "scale_mode.h" +#include "onyx_pb_interface.h" + +/**************************************************************************** +* Macros +****************************************************************************/ + +#define VP8_FOURCC DXL_MKFOURCC( 'V', 'P', '8', '0') + +extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch); + + +/**************************************************************************** +* Typedefs +****************************************************************************/ + +typedef struct // YUV buffer configuration structure +{ + int y_width; + int y_height; + int y_stride; + + int uv_width; + int uv_height; + int uv_stride; + + char *y_buffer; + char *u_buffer; + char *v_buffer; + + char *uv_start; + int uv_dst_area; + int uv_used_area; + + unsigned char *y_ptr_scrn; + unsigned char *u_ptr_scrn; + unsigned char *v_ptr_scrn; + + +} DXV_YUV_BUFFER_CONFIG; + + +typedef void ((*vp8blit_func)(unsigned char *, int, YUV_BUFFER_CONFIG *)); + +/* define an x_image structure based on the core x_image struct */ +typedef struct t_ximage_codec +{ + DXV_YUV_BUFFER_CONFIG frame_buffer; + VP8D_COMP *my_pbi; + VP8_COMMON *common; + int owned; + int decompressed_once; + + int sizeof_pixel; + vp8blit_func blitter; + + unsigned int ppl_tag; + unsigned int bd_tag; + unsigned int *supported_output_format_list; + + int cpu_free; + int postproc; + int add_noise; + int deinterlace; + + int post_proc2time; + int post_proc4time; + + int hs; + int hr; + int vs; + int vr; + YV12_BUFFER_CONFIG this_buffer; + YV12_BUFFER_CONFIG scaled_buffer; + YV12_BUFFER_CONFIG *passed_in_buffer; + + int avgq; + int ppcount; + + +} VP8_XIMAGE, *VP8_XIMAGE_HANDLE; + + +/**************************************************************************** +* Modul Statics +****************************************************************************/ +static unsigned int g_vp8_preferred_output_format_list[] = +{ + VPXDXV_YUY2, + VPXDXV_UYVY, + VPXDXV_RGB8888, + VPXDXV_RGB888, + VPXDXV_RGB555, + VPXDXV_RGB565, + VPXDXV_YV12, + VPXDXV_I420, + +// VPXDXV_YV12, +// VPXDXV_YUY2, +// VPXDXV_RGB565, +// VPXDXV_UYVY, + 0 +}; + +/**************************************************************************** +* Forward declarationss +****************************************************************************/ +void onyx_set_parameter(XIMAGE_HANDLE src, int Command, unsigned int Parameter); + +static int onyx_get_output_format(XIMAGE_HANDLE src, unsigned int *bd_tag); +static int onyx_set_output_format(XIMAGE_HANDLE src, unsigned int bd_tag); + +static int vpx_get_size_of_pixel(unsigned int bd); + +/**************************************************************************** +* Imports +****************************************************************************/ + +#define __Clamp255(x) (unsigned char) ( (x) < 0 ? 0 : ( (x) <= 255 ? (x) : 255 ) ) + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +void +convert_yv12_buffer_types(YV12_BUFFER_CONFIG *source, DXV_YUV_BUFFER_CONFIG *dest) +{ + dest->y_buffer = (char *)source->y_buffer; + dest->u_buffer = (char *)source->u_buffer; + dest->v_buffer = (char *)source->v_buffer; + dest->y_width = source->y_width; + dest->y_height = source->y_height; + dest->y_stride = source->y_stride; + dest->uv_width = source->uv_width; + dest->uv_height = source->uv_height; + dest->uv_stride = source->uv_stride; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + + +int onyx_blit +( + XIMAGE_HANDLE src, + VSCREEN_HANDLE v_screen, + DXV_YUV_BUFFER_CONFIG *frame_buffer, + int x, + int y +) +{ + VP8_XIMAGE_HANDLE tab = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + VP8D_COMP *pbi; + VP8_COMMON *common = tab->common; + pbi = tab->my_pbi; + + if (v_screen) /* if there is a v_screen, blit to it */ + { + unsigned char *ptr_scrn; + int this_pitch, vs_height, vs_width; + unsigned int start_tick, stop_tick; + + vpxdxv_get_vscreen_attributes(v_screen, (void **)&ptr_scrn, &vs_width, &vs_height, &this_pitch); + + if (ptr_scrn) + { + int w, h; + + int p_size; + int view_x, view_y, view_w; + int hs, hr, vs, vr; + int neww, newh; + int cw, ch; + int microseconds_available = (int)(1000000 / 30); + + microseconds_available = microseconds_available * tab->cpu_free / 100; + + if (pbi) + { + microseconds_available -= pbi->decode_microseconds; + + if (tab->cpu_free == 0) + microseconds_available = INT_MAX; + + if (tab->post_proc2time == 0) + tab->post_proc2time = pbi->decode_microseconds * 1 / 2; + + if (tab->post_proc4time == 0) + tab->post_proc4time = pbi->decode_microseconds; + } + + + if (tab->ppcount == 0) + { + tab->post_proc2time = 0; + tab->post_proc4time = 0; + tab->ppcount = 64; + } + else + { + tab->ppcount --; + } + + vpxdxv_get_vscreen_view(v_screen, &view_x, &view_y, &view_w, NULL); + + Scale2Ratio(common->horiz_scale, &hr, &hs); + Scale2Ratio(common->vert_scale, &vr, &vs); + + if (tab->postproc && tab->passed_in_buffer == 0) + { + int show_text = 0; + + unsigned char message[512]; + + int pp = tab->postproc; + int q = (tab->avgq + 4) / 8; + int noise = 0; + + vp8_clear_system_state(); + + if (pp >= 1000) + { + pp -= 1000; + noise = pp / 100; + pp = pp - noise * 100; + } + + if (pp >= 300) + { + pp -= 300; + show_text = 3; + } + else if (pp >= 200) + { + pp -= 200; + show_text = 2; + } + else if (pp >= 100) + { + pp -= 100; + show_text = 1; + } + + if (pbi && (pbi->mb.segmentation_enabled & SEGMENT_PF) && tab->deinterlace) + { + de_interlace(common->frame_to_show->y_buffer, common->post_proc_buffer.y_buffer, + common->post_proc_buffer.y_width, common->post_proc_buffer.y_height, + common->post_proc_buffer.y_stride); + + de_interlace(common->frame_to_show->u_buffer, common->post_proc_buffer.u_buffer, + common->post_proc_buffer.uv_width, common->post_proc_buffer.uv_height, + common->post_proc_buffer.uv_stride); + de_interlace(common->frame_to_show->v_buffer, common->post_proc_buffer.v_buffer, + common->post_proc_buffer.uv_width, common->post_proc_buffer.uv_height, + common->post_proc_buffer.uv_stride); + } + else + { + if (pp >= 10 && pp <= 20) + { + q = q + (pp - 15) * 10; + + if (q < 0) + q = 0; + } + + start_tick = vp8_get_high_res_timer_tick(); + + if (pp > 3 && tab->post_proc4time < microseconds_available) + { + vp8_deblock_and_de_macro_block(common->frame_to_show, &common->post_proc_buffer, q, 1, 0); + + stop_tick = vp8_get_high_res_timer_tick(); + + if (pbi) + tab->post_proc4time = vp8_get_time_in_micro_sec(start_tick, stop_tick); + } + + else if (pp > 0 && tab->post_proc2time < microseconds_available) + { + vp8_deblock(common->frame_to_show, &common->post_proc_buffer, q , 1, 0); + stop_tick = vp8_get_high_res_timer_tick(); + + if (pbi) + tab->post_proc2time = vp8_get_time_in_micro_sec(start_tick, stop_tick); + } + else + { + vp8_yv12_copy_frame(common->frame_to_show, &common->post_proc_buffer); + } + + } + + vp8_clear_system_state(); + + if (tab->add_noise == 1) + { + + vp8_plane_add_noise(common->post_proc_buffer.y_buffer, + common->post_proc_buffer.y_width, common->post_proc_buffer.y_height, + common->post_proc_buffer.y_stride, 63 - q, noise); + } + + + if (show_text == 1) + { +#ifdef PACKET_TESTING + { + VP8_HEADER *oh2 = (VP8_HEADER *) pbi->Source; + sprintf(message, "%8d %d%d%d%d%d size:%d\n", + oh2->frame_number , + oh2->update_gold , + oh2->update_last , + oh2->uses_gold , + oh2->uses_last , + oh2->type, + vpxdxv_get_ximage_csize(src)); + } +#else + sprintf(message, "F:%1ldG:%1ldQ:%3ldF:%3ld,%3ldP:%d_s:%6ld,N:%d,", + (common->frame_type == KEY_FRAME), + common->refresh_golden_frame, + common->base_qindex, + common->filter_level, + q, + tab->postproc, + vpxdxv_get_ximage_csize(src), noise); +#endif + + vp8_blit_text(message, common->post_proc_buffer.y_buffer, common->post_proc_buffer.y_stride); + + } + else if (show_text == 2) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &common->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = common->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + // vp8_filter each macro block + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + if (pp == 4) + sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a'); + else + sprintf(zz, "%c", mi[mb_index].mbmi.ref_frame + 'a'); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + mb_index ++; //border + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + else if (show_text == 3) + { + int i, j; + unsigned char *y_ptr; + YV12_BUFFER_CONFIG *post = &common->post_proc_buffer; + int mb_rows = post->y_height >> 4; + int mb_cols = post->y_width >> 4; + int mb_index = 0; + MODE_INFO *mi = common->mi; + + y_ptr = post->y_buffer + 4 * post->y_stride + 4; + + // vp8_filter each macro block + for (i = 0; i < mb_rows; i++) + { + for (j = 0; j < mb_cols; j++) + { + char zz[4]; + + if (j == 0) + sprintf(zz, "%c", '0' + i % 10); + else + sprintf(zz, "%c", '0' + j % 10); + + vp8_blit_text(zz, y_ptr, post->y_stride); + mb_index ++; + y_ptr += 16; + } + + y_ptr += post->y_stride * 16 - post->y_width; + + } + } + + vpx_memcpy(&tab->this_buffer, &common->post_proc_buffer, sizeof(YV12_BUFFER_CONFIG)); + } + else + { + vpx_memcpy(&tab->this_buffer, common->frame_to_show, sizeof(YV12_BUFFER_CONFIG)); + } + + + /* get a frame pointer to the scaled and postprocessed reconstructed buffer */ + if (tab->passed_in_buffer == 0) + { + if (common->horiz_scale != NORMAL || common->vert_scale != NORMAL) + { + neww = hs * tab->this_buffer.y_width / hr; + newh = vs * tab->this_buffer.y_height / vr; + + neww += neww & 1; + + if (tab->hs != hs || tab->hr != hr || tab->vs != vs || tab->vr != vr) + { + vp8_yv12_alloc_frame_buffer(&tab->scaled_buffer, neww, newh , 8); + } + + vp8_yv12_scale_or_center(&tab->this_buffer, + &tab->scaled_buffer, + neww, newh, SCALE_TO_FIT, hs, hr, vs, vr); + + convert_yv12_buffer_types(&tab->scaled_buffer, frame_buffer); + + cw = hs * common->Width / hr; + ch = vs * common->Height / vr; + + } + else + { + convert_yv12_buffer_types(&tab->this_buffer, frame_buffer); + + cw = common->Width; + ch = common->Height; + } + } + else + { + convert_yv12_buffer_types(tab->passed_in_buffer, frame_buffer); + cw = common->Width; + ch = common->Height; + tab->passed_in_buffer = 0; + } + + frame_buffer->y_width = cw; + frame_buffer->y_height = ch; + frame_buffer->uv_width = cw / 2; + frame_buffer->uv_height = ch / 2; + + p_size = vpx_get_size_of_pixel(tab->bd_tag); + + /* remember to offset if requested */ + y += view_y; + x += view_x ; + + /* for planar destinations */ + w = view_w; + h = vs_height; + + if (w < frame_buffer->y_width) + { + frame_buffer->y_width = w; + frame_buffer->uv_width = (w + 1) / 2; + } + + if (h < frame_buffer->y_height) + { + frame_buffer->y_height = h; + frame_buffer->uv_height = (h + 1) / 2; + } + + if (frame_buffer->y_width < view_w) + x += (view_w - frame_buffer->y_width) / 2; + + if (x & 1) + x -= 1; + + if (frame_buffer->y_height < vs_height) + y += (vs_height - frame_buffer->y_height) / 2; + + + ptr_scrn += (x * p_size) + (y * this_pitch); + + frame_buffer->y_stride *= -1; + frame_buffer->uv_stride *= -1; + + if (tab->bd_tag == VPXDXV_YV12 || tab->bd_tag == VPXDXV_I420) + { + if (this_pitch < 0) + { + frame_buffer->uv_start = (char *)(ptr_scrn + abs(this_pitch) + abs(this_pitch) * h / 4 + this_pitch / 2); + frame_buffer->uv_dst_area = abs((this_pitch * h) / 4); + frame_buffer->uv_used_area = 0; + } + else + { + frame_buffer->uv_start = (char *)(ptr_scrn + (this_pitch * h)); + frame_buffer->uv_dst_area = (((this_pitch + 1) / 2) * ((h + 1) / 2)); + frame_buffer->uv_used_area = (((this_pitch + 1) / 2) * frame_buffer->uv_height); + } + } + + if ((pbi->mb.segmentation_enabled & SEGMENT_PF) && (tab->bd_tag != VPXDXV_YV12 && tab->bd_tag != VPXDXV_I420)) + { + int ypitch = frame_buffer->y_stride; + int uvpitch = frame_buffer->uv_stride; + + frame_buffer->y_stride <<= 1; + frame_buffer->y_height >>= 1; + frame_buffer->uv_stride <<= 1; + frame_buffer->uv_height >>= 1; + + ptr_scrn += this_pitch; + frame_buffer->y_buffer -= ypitch; + frame_buffer->u_buffer -= uvpitch; + frame_buffer->v_buffer -= uvpitch; + tab->blitter(ptr_scrn, 2 * this_pitch, (YUV_BUFFER_CONFIG *)(&tab->frame_buffer)); + + ptr_scrn -= this_pitch; + frame_buffer->y_buffer += ypitch; + frame_buffer->u_buffer += uvpitch; + frame_buffer->v_buffer += uvpitch; + tab->blitter(ptr_scrn, 2 * this_pitch, (YUV_BUFFER_CONFIG *)(&tab->frame_buffer)); + + } + else + { + /* blit the screen */ + tab->blitter(ptr_scrn, this_pitch, (YUV_BUFFER_CONFIG *)(&tab->frame_buffer)); + vpx_log("Decoder: Frame shown \n"); + } + + } + else + vpx_log("Decoder: Frame not shown scrn pointer 0\n"); + } + else + vpx_log("Decoder: Frame not shown vscreen 0\n"); + + return DXV_OK; +} +/**************************************************************************** + * + * ROUTINE : onyx_decompress + * + * INPUTS : None + * + * OUTPUTS : None + * + * RETURNS : None. + * + * FUNCTION : + * + * SPECIAL NOTES : + * + ****************************************************************************/ +static +int onyx_decompress(XIMAGE_HANDLE src, VSCREEN_HANDLE v_screen) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + unsigned char *c_addr; + unsigned int c_size; + int w, h, x, y; + int vp8_rv; + + c_addr = vpxdxv_get_ximage_cdata_addr(src); + c_size = vpxdxv_get_ximage_csize(src); + vpxdxv_get_ximage_xywh(src, &x, &y, &w, &h); + + // if we have a compressed frame decompress it ( otherwise we'll just redo + // the scaling and postprocessing from the last frame ) + if (c_addr) + { + if (c_size != 0) + { + int flags; + int ret_val; + + int f; + + // decode the frame + ret_val = vp8d_decompress_frame((VP8D_PTR) this_algorithm_base->my_pbi, + c_size, + (char *) c_addr, + &this_algorithm_base->this_buffer, + &flags); + + + f = this_algorithm_base->my_pbi->common.filter_level * 10 / 6; + + if (this_algorithm_base->my_pbi->common.frame_type == KEY_FRAME) + this_algorithm_base->avgq = 8 * f; + else + this_algorithm_base->avgq = this_algorithm_base->avgq * 7 / 8 + f; + + + + if (ret_val != 0) + { + if (ret_val == -1) + return DXV_VERSION_CONFLICT; + else + return DXV_BAD_DATA; + } + + } + } + + + vp8_rv = onyx_blit(src, v_screen, &this_algorithm_base->frame_buffer, x, y); + + + return vp8_rv; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static +int vp8_ximagedestroy(XIMAGE_HANDLE src) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + if (this_algorithm_base) + { + + vp8_yv12_de_alloc_frame_buffer(&this_algorithm_base->scaled_buffer); + + /* safety check in case stopdecode was not called */ + if (this_algorithm_base->owned) + vp8dx_remove_decompressor((VP8D_PTR)(this_algorithm_base->my_pbi)); + + duck_free(this_algorithm_base); + } + + return DXV_OK; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static int +onyx_get_post_proc(XIMAGE_HANDLE src, unsigned int *ppl) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + if (this_algorithm_base) + { + *ppl = this_algorithm_base->ppl_tag; + + return DXV_OK; + } + + return DXV_NULL_BASE; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static int +onyx_set_post_proc(XIMAGE_HANDLE src, unsigned int ppl) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + if (this_algorithm_base) + { + this_algorithm_base->ppl_tag = ppl; + + return DXV_OK; + } + + return DXV_NULL_BASE; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static +int vp8_ximagestop_decode(XIMAGE_HANDLE src) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + if (this_algorithm_base) + { + + vp8_yv12_de_alloc_frame_buffer(&this_algorithm_base->scaled_buffer); + + if (this_algorithm_base->owned) + vp8dx_remove_decompressor((VP8D_PTR)(this_algorithm_base->my_pbi)); + + this_algorithm_base->owned = 0; + } + + return DXV_OK; +} + + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static +int vp8_ximagestart_decode +( + XIMAGE_HANDLE src +) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + XIMAGE_INFO_PTR xinfo = vpxdxv_get_ximage_info(src); + VP8D_CONFIG ocf; + + if (xinfo) + { + ocf.Width = xinfo->width; + ocf.Height = xinfo->height; + } + + if (this_algorithm_base->common == 0) + { + this_algorithm_base->my_pbi = (VP8D_COMP *) vp8dx_create_decompressor(&ocf); + this_algorithm_base->owned = 1; + this_algorithm_base->common = &this_algorithm_base->my_pbi->common; + this_algorithm_base->avgq = 0; + + } + + this_algorithm_base->passed_in_buffer = 0; + this_algorithm_base->post_proc2time = 0; + this_algorithm_base->post_proc4time = 0; + this_algorithm_base->ppcount = 64; + + return DXV_OK; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static +DXV_HANDLE vp8_ximagecreate(XIMAGE_HANDLE src) +{ + VP8_XIMAGE_HANDLE this_algorithm_base; + + /* create a new algorithm base container */ + this_algorithm_base = (VP8_XIMAGE_HANDLE)duck_calloc(1, sizeof(VP8_XIMAGE), DMEM_GENERAL); + + if (this_algorithm_base == NULL) + return NULL; + + vp8_scale_machine_specific_config(); + + vpxdxv_register_ximage_start_decode(src, vp8_ximagestart_decode); + + vpxdxv_register_ximage_stop_decode(src, vp8_ximagestop_decode); + + vpxdxv_register_ximage_destroy(src, vp8_ximagedestroy); + + vpxdxv_register_ximage_dx(src, onyx_decompress); + + vpxdxv_register_ximage_set_parameter(src, onyx_set_parameter); + + vpxdxv_register_ximage_output_format_func(src, + onyx_get_output_format, + onyx_set_output_format); + + vpxdxv_register_ximage_post_proc_level_func(src, + onyx_get_post_proc, + onyx_set_post_proc); + + return (DXV_HANDLE)this_algorithm_base; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ + +static int store_output_list(unsigned int supported, int count, + unsigned int *outlist) +{ + int i = 0, j = 0, + ret = DXV_OK; + + while (i < count) + { + while (supported && !(supported & 0x01)) + { + supported >>= 1; + ++j; + } + + *(outlist + i) = g_vp8_preferred_output_format_list[j]; + ++i; + ++j; + supported >>= 1; + } + + + return ret; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static int onyx_get_output_list(XIMAGE_INFO_PTR xinfo, unsigned int *outlist, + unsigned int *size) +{ + int i, + ret = DXV_INVALID_REQUEST; + unsigned int supported = 0, + count = 0; + (void)xinfo; + + if (size) + { + for (i = 0; i < sizeof(g_vp8_preferred_output_format_list) / sizeof(unsigned int) && i < 32; ++i) + { + if (vpx_get_blitter(g_vp8_preferred_output_format_list[i]) != (void *)0xffffffff) + { + supported |= (1 << i); + ++count; + } + } + + if (outlist) + { + if (count && ((count + 1) == (*size / sizeof(int)))) + ret = store_output_list(supported, count, outlist); + else + *outlist = 0; + } + else + { + *size = (count + 1) * sizeof(int); + ret = DXV_OK; + } + } + + return ret; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +int onyx_init(void) +{ + int vp8_rv; + + /* register VPX blitters based on cpu */ + vpx_set_blit(); + + vp8_rv = vpxdxv_register_ximage(vp8_ximagecreate, onyx_get_output_list, VP8_FOURCC); + return vp8_rv; + + return DXV_OK; +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +int onyx_exit(void) +{ + + vpxdxv_un_register_ximage(VP8_FOURCC); + + return DXV_OK; +} +/**************************************************************************** + * + * ROUTINE : onyx_set_parameter + * + * INPUTS : XIMAGE_HANDLE src : + * int Command : + * unsigned long Parameter : + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : + * + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void onyx_set_parameter(XIMAGE_HANDLE src, int Command, unsigned int Parameter) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + switch (Command) + { + case PBC_SET_CPUFREE: + this_algorithm_base->cpu_free = Parameter; + break; + case PBC_SET_POSTPROC: + this_algorithm_base->postproc = Parameter; + break; + + case PBC_SET_BLITBUFF: + this_algorithm_base->passed_in_buffer = (YV12_BUFFER_CONFIG *) Parameter; + break; + + case PBC_SET_REFERENCEFRAME: + { + VP8_XIMAGE_HANDLE tab = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + VP8D_COMP *pbi; + pbi = tab->my_pbi; + vp8_yv12_copy_frame((YV12_BUFFER_CONFIG *) Parameter, &pbi->common.last_frame); + } + break; + + case PBC_SET_COMMON: + + if (Parameter) + { + this_algorithm_base->common = (VP8_COMMON *)Parameter; + } + + break; + case PBC_SET_ADDNOISE: + this_algorithm_base->add_noise = Parameter; + break; + case PBC_SET_DEINTERLACEMODE: + this_algorithm_base->deinterlace = Parameter; + break; + + } +} +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static int +onyx_get_output_format(XIMAGE_HANDLE src, unsigned int *format_tag) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + + if (this_algorithm_base) + { + *format_tag = this_algorithm_base->bd_tag; + return DXV_OK; + } + + return DXV_NULL_BASE; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +static int +onyx_set_output_format(XIMAGE_HANDLE src, unsigned int bd_tag) +{ + VP8_XIMAGE_HANDLE this_algorithm_base = (VP8_XIMAGE_HANDLE)vpxdxv_get_algorithm_base_ptr(src); + int i; + unsigned int bd_tag_found; + + if (this_algorithm_base) + { + i = 0; + bd_tag_found = 0; + + while (g_vp8_preferred_output_format_list[i] != 0) + { + if (g_vp8_preferred_output_format_list[i] == bd_tag) + { + bd_tag_found = 1; + break; + } + + i++; + } + + if (bd_tag_found) + { + this_algorithm_base->blitter = (vp8blit_func)vpx_get_blitter(bd_tag); + this_algorithm_base->bd_tag = bd_tag; + return DXV_OK; + } + + return DXV_INVALID_BLIT; + } + + return DXV_NULL_BASE; +} + +/* +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*/ +int +vpx_get_size_of_pixel(unsigned int bd) +{ + int vp8_rv; + + switch (bd) + { + case VPXDXV_YV12: + case VPXDXV_I420: + vp8_rv = 1; + break; + +#ifdef _ENABLE_SPLIT_PIXEL_ + case VPXDXV_SPLIT565: +#endif + case VPXDXV_RGB555: + case VPXDXV_RGB565: + case VPXDXV_YUY2: + case VPXDXV_UYVY: + case VPXDXV_YVYU: + vp8_rv = 2; + break; + + case VPXDXV_RGB888: + vp8_rv = 3; + break; + + case VPXDXV_RGB8888: + vp8_rv = 4; + break; + + default: + vp8_rv = -1; + break; + } + + return vp8_rv; +}
diff --git a/vp8/decoder/x86/x86_dsystemdependent.c b/vp8/decoder/x86/x86_dsystemdependent.c new file mode 100644 index 0000000..6d7cc36 --- /dev/null +++ b/vp8/decoder/x86/x86_dsystemdependent.c
@@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "vpx_ports/x86.h" +#include "onyxd_int.h" + + +#if HAVE_MMX +void vp8_dequantize_b_impl_mmx(short *sq, short *dq, short *q); + +void vp8_dequantize_b_mmx(BLOCKD *d) +{ + short *sq = (short *) d->qcoeff; + short *dq = (short *) d->dqcoeff; + short *q = (short *) d->dequant; + vp8_dequantize_b_impl_mmx(sq, dq, q); +} +#endif + +void vp8_arch_x86_decode_init(VP8D_COMP *pbi) +{ + int flags = x86_simd_caps(); + + /* Note: + * + * This platform can be built without runtime CPU detection as well. If + * you modify any of the function mappings present in this file, be sure + * to also update them in static mapings (<arch>/filename_<arch>.h) + */ +#if CONFIG_RUNTIME_CPU_DETECT + /* Override default functions with fastest ones for this CPU. */ +#if HAVE_MMX + + if (flags & HAS_MMX) + { + pbi->dequant.block = vp8_dequantize_b_mmx; + pbi->dequant.idct = vp8_dequant_idct_mmx; + pbi->dequant.idct_dc = vp8_dequant_dc_idct_mmx; + } + +#endif +#endif +}
diff --git a/vp8/decoder/xprintf.c b/vp8/decoder/xprintf.c new file mode 100644 index 0000000..cb2221c --- /dev/null +++ b/vp8/decoder/xprintf.c
@@ -0,0 +1,163 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : xprintf.cpp +* +* Description : Display a printf style message on the current video frame. +* +****************************************************************************/ + +/**************************************************************************** +* Header Files +****************************************************************************/ + +#include <stdio.h> +#include <stdarg.h> +#ifdef _WIN32_WCE +#include <windows.h> +#endif +#include "xprintf.h" + +/**************************************************************************** + * + * ROUTINE : xprintf + * + * INPUTS : const PB_INSTANCE *ppbi : Pointer to decoder instance. + * long n_pixel : Offset into buffer to write text. + * const char *format : Format string for print. + * ... : Variable length argument list. + * + * OUTPUTS : None. + * + * RETURNS : int: Size (in bytes) of the formatted text. + * + * FUNCTION : Display a printf style message on the current video frame. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +int onyx_xprintf(unsigned char *ppbuffer, long n_pixel, long n_size, long n_stride, const char *format, ...) +{ + BOOL b_rc; + va_list arglist; + HFONT hfont, hfonto; + + int rc = 0; + char sz_formatted[256] = ""; + unsigned char *p_dest = &ppbuffer[n_pixel]; + +#ifdef _WIN32_WCE + // Set up temporary bitmap + HDC hdc_memory = NULL; + HBITMAP hbm_temp = NULL; + HBITMAP hbm_orig = NULL; + + RECT rect; + + // Copy bitmap to video frame + long x; + long y; + + // Format text + va_start(arglist, format); + _vsnprintf(sz_formatted, sizeof(sz_formatted), format, arglist); + va_end(arglist); + + rect.left = 0; + rect.top = 0; + rect.right = 8 * strlen(sz_formatted); + rect.bottom = 8; + + hdc_memory = create_compatible_dc(NULL); + + if (hdc_memory == NULL) + goto Exit; + + hbm_temp = create_bitmap(rect.right, rect.bottom, 1, 1, NULL); + + if (hbm_temp == NULL) + goto Exit; + + hbm_orig = (HBITMAP)(select_object(hdc_memory, hbm_temp)); + + if (!hbm_orig) + goto Exit; + + // Write text into bitmap + // font? + hfont = create_font(8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, VARIABLE_PITCH | FF_SWISS, ""); + + if (hfont == NULL) + goto Exit; + + hfonto = (HFONT)(select_object(hdc_memory, hbm_temp)); + + if (!hfonto) + goto Exit; + + select_object(hdc_memory, hfont); + set_text_color(hdc_memory, 1); + set_bk_color(hdc_memory, 0); + set_bk_mode(hdc_memory, TRANSPARENT); + + b_rc = bit_blt(hdc_memory, rect.left, rect.top, rect.right, rect.bottom, hdc_memory, rect.left, rect.top, BLACKNESS); + + if (!b_rc) + goto Exit; + + b_rc = ext_text_out(hdc_memory, 0, 0, ETO_CLIPPED, &rect, sz_formatted, strlen(sz_formatted), NULL); + + if (!b_rc) + goto Exit; + + for (y = rect.top; y < rect.bottom; ++y) + { + for (x = rect.left; x < rect.right; ++x) + { + if (get_pixel(hdc_memory, x, rect.bottom - 1 - y)) + p_dest[x] = 255; + } + + p_dest += n_stride; + } + + rc = strlen(sz_formatted); + +Exit: + + if (hbm_temp != NULL) + { + if (hbm_orig != NULL) + { + select_object(hdc_memory, hbm_orig); + } + + delete_object(hbm_temp); + } + + if (hfont != NULL) + { + if (hfonto != NULL) + select_object(hdc_memory, hfonto); + + delete_object(hfont); + } + + if (hdc_memory != NULL) + delete_dc(hdc_memory); + + hdc_memory = 0; + +#endif + + return rc; +}
diff --git a/vp8/decoder/xprintf.h b/vp8/decoder/xprintf.h new file mode 100644 index 0000000..2f175e9 --- /dev/null +++ b/vp8/decoder/xprintf.h
@@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : xprintf.h +* +* Description : Debug print interface header file. +* +****************************************************************************/ +#ifndef __INC_XPRINTF_H +#define __INC_XPRINTF_H + +/**************************************************************************** +* Header Files +****************************************************************************/ + +/**************************************************************************** +* Functions +****************************************************************************/ + +// Display a printf style message on the current video frame +extern int onyx_xprintf(unsigned char *ppbuffer, long n_pixel, long n_size, long n_stride, const char *format, ...); + +#endif
diff --git a/vp8/encoder/arm/armv6/walsh_v6.asm b/vp8/encoder/arm/armv6/walsh_v6.asm new file mode 100644 index 0000000..608c9ae --- /dev/null +++ b/vp8/encoder/arm/armv6/walsh_v6.asm
@@ -0,0 +1,144 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + EXPORT |vp8_short_walsh4x4_armv6| + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY ; name this block of code + +;short vp8_short_walsh4x4_armv6(short *input, short *output, int pitch) +|vp8_short_walsh4x4_armv6| PROC + + stmdb sp!, {r4 - r11, lr} + + mov r12, r2 ; ugh. not clean + ldr r2, [r0] ; [1 | 0] + ldr r3, [r0, #4] ; [3 | 2] + ldr r4, [r0, r12]! ; [5 | 4] + ldr r5, [r0, #4] ; [7 | 6] + ldr r6, [r0, r12]! ; [9 | 8] + ldr r7, [r0, #4] ; [11 | 10] + ldr r8, [r0, r12]! ; [13 | 12] + ldr r9, [r0, #4] ; [15 | 14] + + qsubaddx r10, r2, r3 ; [c1|a1] [1-2 | 0+3] + qaddsubx r11, r2, r3 ; [b1|d1] [1+2 | 0-3] + qsubaddx r12, r4, r5 ; [c1|a1] [5-6 | 4+7] + qaddsubx lr, r4, r5 ; [b1|d1] [5+6 | 4-7] + + qaddsubx r2, r10, r11 ; [1 | 2] [c1+d1 | a1-b1] + qaddsubx r3, r11, r10 ; [0 | 3] [b1+a1 | d1-c1] + qaddsubx r4, r12, lr ; [5 | 6] [c1+d1 | a1-b1] + qaddsubx r5, lr, r12 ; [4 | 7] [b1+a1 | d1-c1] + + qsubaddx r10, r6, r7 ; [c1|a1] [9-10 | 8+11] + qaddsubx r11, r6, r7 ; [b1|d1] [9+10 | 8-11] + qsubaddx r12, r8, r9 ; [c1|a1] [13-14 | 12+15] + qaddsubx lr, r8, r9 ; [b1|d1] [13+14 | 12-15] + + qaddsubx r6, r10, r11 ; [9 |10] [c1+d1 | a1-b1] + qaddsubx r7, r11, r10 ; [8 |11] [b1+a1 | d1-c1] + qaddsubx r8, r12, lr ; [13|14] [c1+d1 | a1-b1] + qaddsubx r9, lr, r12 ; [12|15] [b1+a1 | d1-c1] + + ; first transform complete + + qadd16 r10, r3, r9 ; a1 [0+12 | 3+15] + qadd16 r11, r5, r7 ; b1 [4+8 | 7+11] + qsub16 r12, r5, r7 ; c1 [4-8 | 7-11] + qsub16 lr, r3, r9 ; d1 [0-12 | 3-15] + + qadd16 r3, r10, r11 ; a2 [a1+b1] [0 | 3] + qadd16 r5, r12, lr ; b2 [c1+d1] [4 | 7] + qsub16 r7, r10, r11 ; c2 [a1-b1] [8 |11] + qsub16 r9, lr, r12 ; d2 [d1-c1] [12|15] + + qadd16 r10, r2, r8 ; a1 [1+13 | 2+14] + qadd16 r11, r4, r6 ; b1 [5+9 | 6+10] + qsub16 r12, r4, r6 ; c1 [5-9 | 6-10] + qsub16 lr, r2, r8 ; d1 [1-13 | 2-14] + + qadd16 r2, r10, r11 ; a2 [a1+b1] [1 | 2] + qadd16 r4, r12, lr ; b2 [c1+d1] [5 | 6] + qsub16 r6, r10, r11 ; c2 [a1-b1] [9 |10] + qsub16 r8, lr, r12 ; d2 [d1-c1] [13|14] + + ; [a-d]2 += ([a-d]2 > 0) + + asrs r10, r3, #16 + addpl r10, r10, #1 ; [~0] + asrs r11, r2, #16 + addpl r11, r11, #1 ; [~1] + lsl r11, r11, #15 ; [1 | x] + pkhtb r10, r11, r10, asr #1; [1 | 0] + str r10, [r1], #4 + + lsls r11, r2, #16 + addpl r11, r11, #0x10000 ; [~2] + lsls r12, r3, #16 + addpl r12, r12, #0x10000 ; [~3] + asr r12, r12, #1 ; [3 | x] + pkhtb r11, r12, r11, asr #17; [3 | 2] + str r11, [r1], #4 + + asrs r2, r5, #16 + addpl r2, r2, #1 ; [~4] + asrs r3, r4, #16 + addpl r3, r3, #1 ; [~5] + lsl r3, r3, #15 ; [5 | x] + pkhtb r2, r3, r2, asr #1 ; [5 | 4] + str r2, [r1], #4 + + lsls r2, r4, #16 + addpl r2, r2, #0x10000 ; [~6] + lsls r3, r5, #16 + addpl r3, r3, #0x10000 ; [~7] + asr r3, r3, #1 ; [7 | x] + pkhtb r2, r3, r2, asr #17 ; [7 | 6] + str r2, [r1], #4 + + asrs r2, r7, #16 + addpl r2, r2, #1 ; [~8] + asrs r3, r6, #16 + addpl r3, r3, #1 ; [~9] + lsl r3, r3, #15 ; [9 | x] + pkhtb r2, r3, r2, asr #1 ; [9 | 8] + str r2, [r1], #4 + + lsls r2, r6, #16 + addpl r2, r2, #0x10000 ; [~10] + lsls r3, r7, #16 + addpl r3, r3, #0x10000 ; [~11] + asr r3, r3, #1 ; [11 | x] + pkhtb r2, r3, r2, asr #17 ; [11 | 10] + str r2, [r1], #4 + + asrs r2, r9, #16 + addpl r2, r2, #1 ; [~12] + asrs r3, r8, #16 + addpl r3, r3, #1 ; [~13] + lsl r3, r3, #15 ; [13 | x] + pkhtb r2, r3, r2, asr #1 ; [13 | 12] + str r2, [r1], #4 + + lsls r2, r8, #16 + addpl r2, r2, #0x10000 ; [~14] + lsls r3, r9, #16 + addpl r3, r3, #0x10000 ; [~15] + asr r3, r3, #1 ; [15 | x] + pkhtb r2, r3, r2, asr #17 ; [15 | 14] + str r2, [r1] + + ldmia sp!, {r4 - r11, pc} + ENDP ; |vp8_short_walsh4x4_armv6| + + END
diff --git a/vp8/encoder/arm/boolhuff_arm.c b/vp8/encoder/arm/boolhuff_arm.c new file mode 100644 index 0000000..e70b3ad --- /dev/null +++ b/vp8/encoder/arm/boolhuff_arm.c
@@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "boolhuff.h" +#include "blockd.h" + +const unsigned int vp8_prob_cost[256] = +{ + 2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161, 1129, 1099, 1072, 1046, + 1023, 1000, 979, 959, 940, 922, 905, 889, 873, 858, 843, 829, 816, 803, 790, 778, + 767, 755, 744, 733, 723, 713, 703, 693, 684, 675, 666, 657, 649, 641, 633, 625, + 617, 609, 602, 594, 587, 580, 573, 567, 560, 553, 547, 541, 534, 528, 522, 516, + 511, 505, 499, 494, 488, 483, 477, 472, 467, 462, 457, 452, 447, 442, 437, 433, + 428, 424, 419, 415, 410, 406, 401, 397, 393, 389, 385, 381, 377, 373, 369, 365, + 361, 357, 353, 349, 346, 342, 338, 335, 331, 328, 324, 321, 317, 314, 311, 307, + 304, 301, 297, 294, 291, 288, 285, 281, 278, 275, 272, 269, 266, 263, 260, 257, + 255, 252, 249, 246, 243, 240, 238, 235, 232, 229, 227, 224, 221, 219, 216, 214, + 211, 208, 206, 203, 201, 198, 196, 194, 191, 189, 186, 184, 181, 179, 177, 174, + 172, 170, 168, 165, 163, 161, 159, 156, 154, 152, 150, 148, 145, 143, 141, 139, + 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 105, 103, 101, 99, 97, 95, 93, 92, 90, 88, 86, 84, 82, 81, 79, 77, + 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 55, 53, 51, 50, + 48, 46, 45, 43, 41, 40, 38, 37, 35, 33, 32, 30, 29, 27, 25, 24, + 22, 21, 19, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 1 +}; +
diff --git a/vp8/encoder/arm/csystemdependent.c b/vp8/encoder/arm/csystemdependent.c new file mode 100644 index 0000000..0039796 --- /dev/null +++ b/vp8/encoder/arm/csystemdependent.c
@@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "variance.h" +#include "onyx_int.h" + +void (*vp8_yv12_copy_partial_frame_ptr)(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); +extern void vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); +extern void vpxyv12_copy_partial_frame_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); + +void vp8_cmachine_specific_config(VP8_COMP *cpi) +{ +#if CONFIG_RUNTIME_CPU_DETECT + cpi->rtcd.common = &cpi->common.rtcd; + +#if HAVE_ARMV7 + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_neon; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_neon; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_neon; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_neon; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_neon; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_c; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_neon; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_neon; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_neon; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_neon; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_c; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_neon; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_c; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_c; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_neon; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_neon; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_neon; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_c; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_c;; + cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_neon; + + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_neon; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_neon; + cpi->rtcd.fdct.fast4x4 = vp8_fast_fdct4x4_neon; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_neon; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_neon; + + cpi->rtcd.encodemb.berr = vp8_block_error_c; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_c; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_c; + cpi->rtcd.encodemb.subb = vp8_subtract_b_neon; + cpi->rtcd.encodemb.submby = vp8_subtract_mby_neon; + cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_neon; + + cpi->rtcd.quantize.quantb = vp8_regular_quantize_b; + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_neon; +#elif HAVE_ARMV6 + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_c; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_c; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_c; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_c; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_c; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_c; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_c; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_c; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_c; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_c; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_c; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_c; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_c; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_c; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_c; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_c; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_c; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_c; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_c;; + cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_c; + + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_c; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_c; + cpi->rtcd.fdct.fast4x4 = vp8_fast_fdct4x4_c; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_c; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_armv6; + + cpi->rtcd.encodemb.berr = vp8_block_error_c; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_c; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_c; + cpi->rtcd.encodemb.subb = vp8_subtract_b_c; + cpi->rtcd.encodemb.submby = vp8_subtract_mby_c; + cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_c; + + cpi->rtcd.quantize.quantb = vp8_regular_quantize_b; + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_c; +#else + //pure c + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_c; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_c; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_c; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_c; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_c; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_c; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_c; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_c; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_c; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_c; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_c; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_c; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_c; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_c; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_c; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_c; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_c; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_c; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_c;; + cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_c; + + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_c; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_c; + cpi->rtcd.fdct.fast4x4 = vp8_fast_fdct4x4_c; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_c; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_c; + + cpi->rtcd.encodemb.berr = vp8_block_error_c; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_c; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_c; + cpi->rtcd.encodemb.subb = vp8_subtract_b_c; + cpi->rtcd.encodemb.submby = vp8_subtract_mby_c; + cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_c; + + cpi->rtcd.quantize.quantb = vp8_regular_quantize_b; + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_c; +#endif +#endif + +#if HAVE_ARMV7 + vp8_yv12_copy_partial_frame_ptr = vpxyv12_copy_partial_frame_neon; +#else + vp8_yv12_copy_partial_frame_ptr = vp8_yv12_copy_partial_frame; +#endif +}
diff --git a/vp8/encoder/arm/dct_arm.h b/vp8/encoder/arm/dct_arm.h new file mode 100644 index 0000000..a671862 --- /dev/null +++ b/vp8/encoder/arm/dct_arm.h
@@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DCT_ARM_H +#define DCT_ARM_H + +#if HAVE_ARMV6 +extern prototype_fdct(vp8_short_walsh4x4_armv6); + +#undef vp8_fdct_walsh_short4x4 +#define vp8_fdct_walsh_short4x4 vp8_short_walsh4x4_armv6 +#endif + +#if HAVE_ARMV7 +extern prototype_fdct(vp8_short_fdct4x4_neon); +extern prototype_fdct(vp8_short_fdct8x4_neon); +extern prototype_fdct(vp8_fast_fdct4x4_neon); +extern prototype_fdct(vp8_fast_fdct8x4_neon); +extern prototype_fdct(vp8_short_walsh4x4_neon); + +#undef vp8_fdct_short4x4 +#define vp8_fdct_short4x4 vp8_short_fdct4x4_neon + +#undef vp8_fdct_short8x4 +#define vp8_fdct_short8x4 vp8_short_fdct8x4_neon + +#undef vp8_fdct_fast4x4 +#define vp8_fdct_fast4x4 vp8_fast_fdct4x4_neon + +#undef vp8_fdct_fast8x4 +#define vp8_fdct_fast8x4 vp8_fast_fdct8x4_neon + +#undef vp8_fdct_walsh_short4x4 +#define vp8_fdct_walsh_short4x4 vp8_short_walsh4x4_neon + +#endif + +#endif
diff --git a/vp8/encoder/arm/encodemb_arm.c b/vp8/encoder/arm/encodemb_arm.c new file mode 100644 index 0000000..3f1d053 --- /dev/null +++ b/vp8/encoder/arm/encodemb_arm.c
@@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "encodemb.h" +#include "reconinter.h" +#include "quantize.h" +#include "invtrans.h" +#include "recon.h" +#include "reconintra.h" +#include "dct.h" +#include "vpx_mem/vpx_mem.h" + +extern void vp8_subtract_b_neon_func(short *diff, unsigned char *src, unsigned char *pred, int stride, int pitch); + +void vp8_subtract_b_neon(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *src_ptr = (*(be->base_src) + be->src); + short *diff_ptr = be->src_diff; + unsigned char *pred_ptr = bd->predictor; + int src_stride = be->src_stride; + + vp8_subtract_b_neon_func(diff_ptr, src_ptr, pred_ptr, src_stride, pitch); +}
diff --git a/vp8/encoder/arm/encodemb_arm.h b/vp8/encoder/arm/encodemb_arm.h new file mode 100644 index 0000000..28f9e5c --- /dev/null +++ b/vp8/encoder/arm/encodemb_arm.h
@@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef ENCODEMB_ARM_H +#define ENCODEMB_ARM_H + +#if HAVE_ARMV7 +//extern prototype_berr(vp8_block_error_c); +//extern prototype_mberr(vp8_mbblock_error_c); +//extern prototype_mbuverr(vp8_mbuverror_c); + +extern prototype_subb(vp8_subtract_b_neon); +extern prototype_submby(vp8_subtract_mby_neon); +extern prototype_submbuv(vp8_subtract_mbuv_neon); + +//#undef vp8_encodemb_berr +//#define vp8_encodemb_berr vp8_block_error_c + +//#undef vp8_encodemb_mberr +//#define vp8_encodemb_mberr vp8_mbblock_error_c + +//#undef vp8_encodemb_mbuverr +//#define vp8_encodemb_mbuverr vp8_mbuverror_c + +#undef vp8_encodemb_subb +#define vp8_encodemb_subb vp8_subtract_b_neon + +#undef vp8_encodemb_submby +#define vp8_encodemb_submby vp8_subtract_mby_neon + +#undef vp8_encodemb_submbuv +#define vp8_encodemb_submbuv vp8_subtract_mbuv_neon + +#endif + +#endif
diff --git a/vp8/encoder/arm/mcomp_arm.c b/vp8/encoder/arm/mcomp_arm.c new file mode 100644 index 0000000..07f2186 --- /dev/null +++ b/vp8/encoder/arm/mcomp_arm.c
@@ -0,0 +1,1662 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "mcomp.h" +#include "vpx_mem/vpx_mem.h" + +#include <stdio.h> +#include <limits.h> +#include <math.h> + +#ifdef ENTROPY_STATS +static int mv_ref_ct [31] [4] [2]; +static int mv_mode_cts [4] [2]; +#endif + +static int mv_bits_sadcost[256]; + +extern unsigned int vp8_sub_pixel_variance16x16s_neon +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +); +extern unsigned int vp8_sub_pixel_variance16x16s_4_0_neon +( + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +); +extern unsigned int vp8_sub_pixel_variance16x16s_0_4_neon +( + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +); +extern unsigned int vp8_sub_pixel_variance16x16s_4_4_neon +( + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +); + +void vp8cx_init_mv_bits_sadcost() +{ + int i; + + for (i = 0; i < 256; i++) + { + mv_bits_sadcost[i] = (int)sqrt(i * 16); + } +} + + +int vp8_mv_bit_cost(MV *mv, MV *ref, int *mvcost[2], int Weight) +{ + // MV costing is based on the distribution of vectors in the previous frame and as such will tend to + // over state the cost of vectors. In addition coding a new vector can have a knock on effect on the + // cost of subsequent vectors and the quality of prediction from NEAR and NEAREST for subsequent blocks. + // The "Weight" parameter allows, to a limited extent, for some account to be taken of these factors. + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col) >> 1]) * Weight) >> 7; +} + +int vp8_mv_err_cost(MV *mv, MV *ref, int *mvcost[2], int error_per_bit) +{ + //int i; + //return ((mvcost[0][(mv->row - ref->row)>>1] + mvcost[1][(mv->col - ref->col)>>1] + 128) * error_per_bit) >> 8; + //return ( (vp8_mv_bit_cost(mv, ref, mvcost, 100) + 128) * error_per_bit) >> 8; + + //i = (vp8_mv_bit_cost(mv, ref, mvcost, 100) * error_per_bit + 128) >> 8; + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col) >> 1]) * error_per_bit + 128) >> 8; + //return (vp8_mv_bit_cost(mv, ref, mvcost, 128) * error_per_bit + 128) >> 8; +} + + +static int mv_bits(MV *mv, MV *ref, int *mvcost[2]) +{ + // get the estimated number of bits for a motion vector, to be used for costing in SAD based + // motion estimation + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col)>> 1]) + 128) >> 8; +} + +void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + + // Generate offsets for 4 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 4; +} + +void vp8_init3smotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + // Generate offsets for 8 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride + Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride + Len; + search_site_count++; + + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 8; +} + + +#define MVC(r,c) (((mvcost[0][(r)-rr] + mvcost[1][(c) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (*(d->base_pre) + d->pre + ((r)>>2) * d->pre_stride + ((c)>>2)) // pointer to predictor base of a motionvector +#define SP(x) (((x)&3)<<1) // convert motion vector component to offset for svf calc +#define DIST(r,c) svf( PRE(r,c), d->pre_stride, SP(c),SP(r), z,b->src_stride,&sse) // returns subpixel variance error function. +#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; +#define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) IFMVCV(r,c,{if((v = ERR(r,c)) < besterr) { besterr = v; br=r; bc=c; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define MAX(x,y) (((x)>(y))?(x):(y)) + +//#define CHECK_BETTER(v,r,c) if((v = ERR(r,c)) < besterr) { besterr = v; br=r; bc=c; } + +int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + + int rr = ref_mv->row >> 1, rc = ref_mv->col >> 1; + int br = bestmv->row << 2, bc = bestmv->col << 2; + int tr = br, tc = bc; + unsigned int besterr = INT_MAX; + unsigned int left, right, up, down, diag; + unsigned int sse; + unsigned int whichdir; + unsigned int halfiters = 4; + unsigned int quarteriters = 4; + + int minc = MAX(x->mv_col_min << 2, (ref_mv->col >> 1) - ((1 << mvlong_width) - 1)); + int maxc = MIN(x->mv_col_max << 2, (ref_mv->col >> 1) + ((1 << mvlong_width) - 1)); + int minr = MAX(x->mv_row_min << 2, (ref_mv->row >> 1) - ((1 << mvlong_width) - 1)); + int maxr = MIN(x->mv_row_max << 2, (ref_mv->row >> 1) + ((1 << mvlong_width) - 1)); + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + + // calculate central point error + besterr = vf(y, d->pre_stride, z, b->src_stride, &sse); + besterr += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + while (--halfiters) + { + // 1/2 pel + CHECK_BETTER(left, tr, tc - 2); + CHECK_BETTER(right, tr, tc + 2); + CHECK_BETTER(up, tr - 2, tc); + CHECK_BETTER(down, tr + 2, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 2, tc - 2); + break; + case 1: + CHECK_BETTER(diag, tr - 2, tc + 2); + break; + case 2: + CHECK_BETTER(diag, tr + 2, tc - 2); + break; + case 3: + CHECK_BETTER(diag, tr + 2, tc + 2); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + // 1/4 pel + while (--quarteriters) + { + CHECK_BETTER(left, tr, tc - 1); + CHECK_BETTER(right, tr, tc + 1); + CHECK_BETTER(up, tr - 1, tc); + CHECK_BETTER(down, tr + 1, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 1, tc - 1); + break; + case 1: + CHECK_BETTER(diag, tr - 1, tc + 1); + break; + case 2: + CHECK_BETTER(diag, tr + 1, tc - 1); + break; + case 3: + CHECK_BETTER(diag, tr + 1, tc + 1); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + bestmv->row = br << 1; + bestmv->col = bc << 1; + + if ((abs(bestmv->col - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs(bestmv->row - ref_mv->row) > MAX_FULL_PEL_VAL)) + return INT_MAX; + + return besterr; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef ERR +#undef CHECK_BETTER +#undef MIN +#undef MAX +int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + int bestmse = INT_MAX; + MV startmv; + //MV this_mv; + MV this_mv; + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + int whichdir ; + + + // Trap uncodable vectors + if ((abs((bestmv->col << 3) - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs((bestmv->row << 3) - ref_mv->row) > MAX_FULL_PEL_VAL)) + { + bestmv->row <<= 3; + bestmv->col <<= 3; + return INT_MAX; + } + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vf(y, d->pre_stride, z, b->src_stride, &sse); + bestmse += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.row = startmv.row; + this_mv.col = ((startmv.col - 8) | 4); + left = vp8_sub_pixel_variance16x16s_4_0_neon(y - 1, d->pre_stride, z, b->src_stride, &sse); + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 8; + right = vp8_sub_pixel_variance16x16s_4_0_neon(y, d->pre_stride, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + this_mv.row = ((startmv.row - 8) | 4); + up = vp8_sub_pixel_variance16x16s_0_4_neon(y - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 8; + down = vp8_sub_pixel_variance16x16s_0_4_neon(y, d->pre_stride, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + //for(whichdir =0;whichdir<4;whichdir++) + //{ + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - 1 - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + break; + case 1: + this_mv.col += 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + break; + case 2: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row += 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - 1, d->pre_stride, z, b->src_stride, &sse); + break; + case 3: + this_mv.col += 4; + this_mv.row += 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y, d->pre_stride, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +// } + + + // time to check quarter pels. + if (bestmv->row < startmv.row) + y -= d->pre_stride; + + if (bestmv->col < startmv.col) + y--; + + startmv = *bestmv; + + + + // go left then right and check error + this_mv.row = startmv.row; + + if (startmv.col & 7) + { + this_mv.col = startmv.col - 2; + left = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + left = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse); + } + + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 4; + right = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + + if (startmv.row & 7) + { + this_mv.row = startmv.row - 2; + up = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.row = (startmv.row - 8) | 6; + up = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 4; + down = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + +// for(whichdir=0;whichdir<4;whichdir++) +// { + this_mv = startmv; + + switch (whichdir) + { + case 0: + + if (startmv.row & 7) + { + this_mv.row -= 2; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse);; + } + } + else + { + this_mv.row = (startmv.row - 8) | 6; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - d->pre_stride - 1, d->pre_stride, 6, 6, z, b->src_stride, &sse); + } + } + + break; + case 1: + this_mv.col += 2; + + if (startmv.row & 7) + { + this_mv.row -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.row = (startmv.row - 8) | 6; + diag = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + + break; + case 2: + this_mv.row += 2; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse);; + } + + break; + case 3: + this_mv.col += 2; + this_mv.row += 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +// } + + return bestmse; +} + +int vp8_find_best_half_pixel_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + int bestmse = INT_MAX; + MV startmv; + //MV this_mv; + MV this_mv; + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + + // Trap uncodable vectors + if ((abs((bestmv->col << 3) - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs((bestmv->row << 3) - ref_mv->row) > MAX_FULL_PEL_VAL)) + { + bestmv->row <<= 3; + bestmv->col <<= 3; + return INT_MAX; + } + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vf(y, d->pre_stride, z, b->src_stride, &sse); + bestmse += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.row = startmv.row; + this_mv.col = ((startmv.col - 8) | 4); + left = vp8_sub_pixel_variance16x16s_4_0_neon(y - 1, d->pre_stride, z, b->src_stride, &sse); + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 8; + right = vp8_sub_pixel_variance16x16s_4_0_neon(y, d->pre_stride, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + this_mv.row = ((startmv.row - 8) | 4); + up = vp8_sub_pixel_variance16x16s_0_4_neon(y - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 8; + down = vp8_sub_pixel_variance16x16s_0_4_neon(y, d->pre_stride, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + // somewhat strangely not doing all the diagonals for half pel is slower than doing them. +#if 0 + // now check 1 more diagonal - + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - 1 - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 1: + this_mv.col += 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 2: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row += 4; + diag = svf(y - 1, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 3: + this_mv.col += 4; + this_mv.row += 4; + diag = svf(y, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +#else + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - 1 - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col += 8; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - d->pre_stride, d->pre_stride, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = startmv.row + 4; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y - 1, d->pre_stride, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col += 8; + diag = vp8_sub_pixel_variance16x16s_4_4_neon(y, d->pre_stride, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +#endif + return bestmse; +} + +#if 1 + +#define MVC(r,c) (((mvsadcost[0][((r)<<2)-rr] + mvsadcost[1][((c)<<2) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (*(d->base_pre) + d->pre + (r) * d->pre_stride + (c)) // pointer to predictor base of a motionvector +#define DIST(r,c,v) sf( src,src_stride,PRE(r,c),d->pre_stride, v) // returns sad error score. +#define ERR(r,c,v) (MVC(r,c)+DIST(r,c,v)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) if ((v = ERR(r,c,besterr)) < besterr) { besterr = v; br=r; bc=c; } // checks if (r,c) has better score than previous best +const MV next_chkpts[6][3] = +{ + {{ -2, 0}, { -1, -2}, {1, -2}}, + {{ -1, -2}, {1, -2}, {2, 0}}, + {{1, -2}, {2, 0}, {1, 2}}, + {{2, 0}, {1, 2}, { -1, 2}}, + {{1, 2}, { -1, 2}, { -2, 0}}, + {{ -1, 2}, { -2, 0}, { -1, -2}} +}; +int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_t vf, + vp8_sad_fn_t sf, + int *mvsadcost[2], + int *mvcost[2] +) +{ + MV hex[6] = { { -1, -2}, {1, -2}, {2, 0}, {1, 2}, { -1, 2}, { -2, 0} } ; + MV neighbors[8] = { { -1, -1}, { -1, 0}, { -1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} } ; + int i, j; + unsigned char *src = (*(b->base_src) + b->src); + int src_stride = b->src_stride; + int rr = ref_mv->row, rc = ref_mv->col, br = rr >> 3, bc = rc >> 3, tr, tc; + unsigned int besterr, thiserr = 0x7fffffff; + int k = -1, tk; + + if (bc < x->mv_col_min) bc = x->mv_col_min; + + if (bc > x->mv_col_max) bc = x->mv_col_max; + + if (br < x->mv_row_min) br = x->mv_row_min; + + if (br > x->mv_row_max) br = x->mv_row_max; + + rr >>= 1; + rc >>= 1; + + besterr = ERR(br, bc, thiserr); + + // hex search + //j=0 + tr = br; + tc = bc; + + for (i = 0; i < 6; i++) + { + int nr = tr + hex[i].row, nc = tc + hex[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + //CHECK_BETTER(thiserr,nr,nc); + if ((thiserr = ERR(nr, nc, besterr)) < besterr) + { + besterr = thiserr; + br = nr; + bc = nc; + k = i; + } + } + + if (tr == br && tc == bc) + goto cal_neighbors; + + for (j = 1; j < 127; j++) + { + tr = br; + tc = bc; + tk = k; + + for (i = 0; i < 3; i++) + { + int nr = tr + next_chkpts[tk][i].row, nc = tc + next_chkpts[tk][i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + //CHECK_BETTER(thiserr,nr,nc); + if ((thiserr = ERR(nr, nc, besterr)) < besterr) + { + besterr = thiserr; + br = nr; + bc = nc; //k=(tk+5+i)%6;} + k = tk + 5 + i; + + if (k >= 12) k -= 12; + else if (k >= 6) k -= 6; + } + } + + if (tr == br && tc == bc) + break; + } + + // check 8 1 away neighbors +cal_neighbors: + tr = br; + tc = bc; + + for (i = 0; i < 8; i++) + { + int nr = tr + neighbors[i].row, nc = tc + neighbors[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + CHECK_BETTER(thiserr, nr, nc); + } + + best_mv->row = br; + best_mv->col = bc; + + return vf(src, src_stride, PRE(br, bc), d->pre_stride, &thiserr) + MVC(br, bc) ; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef ERR +#undef CHECK_BETTER + +#else + +#define MVC(r,c) (((mvsadcost[0][((r)<<2)-rr] + mvsadcost[1][((c)<<2) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (*(d->base_pre) + d->pre + (r) * d->pre_stride + (c)) // pointer to predictor base of a motionvector +#define DIST(r,c,v) sf( src,src_stride,PRE(r,c),d->pre_stride, v) // returns sad error score. +#define ERR(r,c,v) (MVC(r,c)+DIST(r,c,v)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) if ((v = ERR(r,c,besterr)) < besterr) { besterr = v; br=r; bc=c; } // checks if (r,c) has better score than previous best + +int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_t vf, + vp8_sad_fn_t sf, + int *mvsadcost[2], + int *mvcost[2] +) +{ + MV hex[6] = { { -2, 0}, { -1, -2}, { -1, 2}, {2, 0}, {1, 2}, {1, -2} } ; + MV neighbors[8] = { { -1, -1}, { -1, 0}, { -1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} } ; + int i, j; + unsigned char *src = (*(b->base_src) + b->src); + int src_stride = b->src_stride; + //int rr= ref_mv->row,rc= ref_mv->col,br=rr,bc=rc,tr,tc; + int rr = ref_mv->row, rc = ref_mv->col, br = rr >> 3, bc = rc >> 3, tr, tc; + unsigned int besterr, thiserr = 0x7fffffff; + + /* + if ( rc < x->mv_col_min) bc = x->mv_col_min; + if ( rc > x->mv_col_max) bc = x->mv_col_max; + if ( rr < x->mv_row_min) br = x->mv_row_min; + if ( rr > x->mv_row_max) br = x->mv_row_max; + rr>>=1; + rc>>=1; + br>>=3; + bc>>=3; + */ + if (bc < x->mv_col_min) bc = x->mv_col_min; + + if (bc > x->mv_col_max) bc = x->mv_col_max; + + if (br < x->mv_row_min) br = x->mv_row_min; + + if (br > x->mv_row_max) br = x->mv_row_max; + + rr >>= 1; + rc >>= 1; + + besterr = ERR(br, bc, thiserr); + + // hex search jbb changed to 127 to avoid max 256 problem steping by 2. + for (j = 0; j < 127; j++) + { + tr = br; + tc = bc; + + for (i = 0; i < 6; i++) + { + int nr = tr + hex[i].row, nc = tc + hex[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + CHECK_BETTER(thiserr, nr, nc); + } + + if (tr == br && tc == bc) + break; + } + + // check 8 1 away neighbors + tr = br; + tc = bc; + + for (i = 0; i < 8; i++) + { + int nr = tr + neighbors[i].row, nc = tc + neighbors[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + CHECK_BETTER(thiserr, nr, nc); + } + + best_mv->row = br; + best_mv->col = bc; + + return vf(src, src_stride, PRE(br, bc), d->pre_stride, &thiserr) + MVC(br, bc) ; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef ERR +#undef CHECK_BETTER + +#endif + +int vp8_diamond_search_sad +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvsadcost[2], + int *mvcost[2] +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + unsigned char *best_address; + + int tot_steps; + MV this_mv; + + int bestsad = INT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + int thissad; + + // Work out the start point for the search + in_what = (unsigned char *)(*(d->base_pre) + d->pre + (ref_row * (d->pre_stride)) + ref_col); + best_address = in_what; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + best_mv->row = ref_row; + best_mv->col = ref_col; + + *num00 = 0; + + for (step = 0; step < tot_steps ; step++) + { + for (j = 0 ; j < x->searches_per_step ; j++) + { + // Trap illegal vectors + this_row_offset = best_mv->row + ss[i].mv.row; + this_col_offset = best_mv->col + ss[i].mv.col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + + { + check_here = ss[i].offset + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.row = this_row_offset << 3; + this_mv.col = this_col_offset << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + + i++; + } + + if (best_site != last_site) + { + best_mv->row += ss[best_site].mv.row; + best_mv->col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +} + +int vp8_diamond_search_sadx4 +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvsadcost[2], + int *mvcost[2] +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + unsigned char *best_address; + + int tot_steps; + MV this_mv; + + int bestsad = INT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + int thissad; + + // Work out the start point for the search + in_what = (unsigned char *)(*(d->base_pre) + d->pre + (ref_row * (d->pre_stride)) + ref_col); + best_address = in_what; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + best_mv->row = ref_row; + best_mv->col = ref_col; + + *num00 = 0; + + for (step = 0; step < tot_steps ; step++) + { + int check_row_min, check_col_min, check_row_max, check_col_max; + + check_row_min = x->mv_row_min - best_mv->row; + check_row_max = x->mv_row_max - best_mv->row; + check_col_min = x->mv_col_min - best_mv->col; + check_col_max = x->mv_col_max - best_mv->col; + + for (j = 0 ; j < x->searches_per_step ; j += 4) + { + char *block_offset[4]; + unsigned int valid_block[4]; + int all_in = 1, t; + + for (t = 0; t < 4; t++) + { + valid_block [t] = (ss[t+i].mv.col > check_col_min); + valid_block [t] &= (ss[t+i].mv.col < check_col_max); + valid_block [t] &= (ss[t+i].mv.row > check_row_min); + valid_block [t] &= (ss[t+i].mv.row < check_row_max); + + all_in &= valid_block[t]; + block_offset[t] = ss[i+t].offset + best_address; + } + + if (all_in) + { + int sad_array[4]; + + fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array); + + for (t = 0; t < 4; t++, i++) + { + thissad = sad_array[t]; + + if (thissad < bestsad) + { + this_mv.row = (best_mv->row + ss[i].mv.row) << 3; + this_mv.col = (best_mv->col + ss[i].mv.col) << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + } + else + { + int t; + + for (t = 0; t < 4; i++, t++) + { + // Trap illegal vectors + if (valid_block[t]) + + { + check_here = block_offset[t]; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_row_offset = best_mv->row + ss[i].mv.row; + this_col_offset = best_mv->col + ss[i].mv.col; + + this_mv.row = this_row_offset << 3; + this_mv.col = this_col_offset << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + } + } + } + + if (best_site != last_site) + { + best_mv->row += ss[best_site].mv.row; + best_mv->col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +} + + +#if !(CONFIG_REALTIME_ONLY) +int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int error_per_bit, int distance, vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], int *mvsadcost[2]) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + int mv_stride = d->pre_stride; + unsigned char *bestaddress; + MV *best_mv = &d->bmi.mv.as_mv; + MV this_mv; + int bestsad = INT_MAX; + int r, c; + + unsigned char *check_here; + int thissad; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + // Work out the mid point for the search + in_what = *(d->base_pre) + d->pre; + bestaddress = in_what + (ref_row * d->pre_stride) + ref_col; + + best_mv->row = ref_row; + best_mv->col = ref_col; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Baseline value at the centre + + //bestsad = fn_ptr->sf( what,what_stride,bestaddress,in_what_stride) + (int)sqrt(vp8_mv_err_cost(ref_mv,ref_mv, mvcost,error_per_bit*14)); + bestsad = fn_ptr->sdf(what, what_stride, bestaddress, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.row = r << 3; + check_here = r * mv_stride + in_what + col_min; + + for (c = col_min; c < col_max; c++) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + this_mv.col = c << 3; + //thissad += (int)sqrt(vp8_mv_err_cost(&this_mv,ref_mv, mvcost,error_per_bit*14)); + //thissad += error_per_bit * mv_bits_sadcost[mv_bits(&this_mv, ref_mv, mvcost)]; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); //mv_bits(error_per_bit, &this_mv, ref_mv, mvsadcost); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + + check_here++; + } + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + else + return INT_MAX; +} + +int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int error_per_bit, int distance, vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], int *mvsadcost[2]) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + int mv_stride = d->pre_stride; + unsigned char *bestaddress; + MV *best_mv = &d->bmi.mv.as_mv; + MV this_mv; + int bestsad = INT_MAX; + int r, c; + + unsigned char *check_here; + int thissad; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + int sad_array[3]; + + // Work out the mid point for the search + in_what = *(d->base_pre) + d->pre; + bestaddress = in_what + (ref_row * d->pre_stride) + ref_col; + + best_mv->row = ref_row; + best_mv->col = ref_col; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Baseline value at the centre + bestsad = fn_ptr->sdf(what, what_stride, bestaddress, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.row = r << 3; + check_here = r * mv_stride + in_what + col_min; + c = col_min; + + while ((c + 3) < col_max) + { + int i; + + fn_ptr->sdx3f(what, what_stride, check_here , in_what_stride, sad_array); + + for (i = 0; i < 3; i++) + { + thissad = sad_array[i]; + + if (thissad < bestsad) + { + this_mv.col = c << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + } + + check_here++; + c++; + } + } + + while (c < col_max) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.col = c << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + } + + check_here ++; + c ++; + } + + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + else + return INT_MAX; +} +#endif + +#ifdef ENTROPY_STATS +void print_mode_context(void) +{ + FILE *f = fopen("modecont.c", "w"); + int i, j; + + fprintf(f, "#include \"entropy.h\"\n"); + fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); + fprintf(f, "{\n"); + + for (j = 0; j < 6; j++) + { + fprintf(f, " { // %d \n", j); + fprintf(f, " "); + + for (i = 0; i < 4; i++) + { + int overal_prob; + int this_prob; + int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1]; + + // Overall probs + count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; + + if (count) + overal_prob = 256 * mv_mode_cts[i][0] / count; + else + overal_prob = 128; + + if (overal_prob == 0) + overal_prob = 1; + + // context probs + count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; + + if (count) + this_prob = 256 * mv_ref_ct[j][i][0] / count; + else + this_prob = 128; + + if (this_prob == 0) + this_prob = 1; + + fprintf(f, "%5d, ", this_prob); + //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob); + //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob); + } + + fprintf(f, " },\n"); + } + + fprintf(f, "};\n"); + fclose(f); +} + +/* MV ref count ENTROPY_STATS stats code */ +#ifdef ENTROPY_STATS +void init_mv_ref_counts() +{ + vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); + vpx_memset(mv_mode_cts, 0, sizeof(mv_mode_cts)); +} + +void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) +{ + if (m == ZEROMV) + { + ++mv_ref_ct [ct[0]] [0] [0]; + ++mv_mode_cts[0][0]; + } + else + { + ++mv_ref_ct [ct[0]] [0] [1]; + ++mv_mode_cts[0][1]; + + if (m == NEARESTMV) + { + ++mv_ref_ct [ct[1]] [1] [0]; + ++mv_mode_cts[1][0]; + } + else + { + ++mv_ref_ct [ct[1]] [1] [1]; + ++mv_mode_cts[1][1]; + + if (m == NEARMV) + { + ++mv_ref_ct [ct[2]] [2] [0]; + ++mv_mode_cts[2][0]; + } + else + { + ++mv_ref_ct [ct[2]] [2] [1]; + ++mv_mode_cts[2][1]; + + if (m == NEWMV) + { + ++mv_ref_ct [ct[3]] [3] [0]; + ++mv_mode_cts[3][0]; + } + else + { + ++mv_ref_ct [ct[3]] [3] [1]; + ++mv_mode_cts[3][1]; + } + } + } + } +} + +#endif/* END MV ref count ENTROPY_STATS stats code */ + +#endif
diff --git a/vp8/encoder/arm/neon/boolhuff_armv7.asm b/vp8/encoder/arm/neon/boolhuff_armv7.asm new file mode 100644 index 0000000..9a5f366 --- /dev/null +++ b/vp8/encoder/arm/neon/boolhuff_armv7.asm
@@ -0,0 +1,292 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_start_encode| + EXPORT |vp8_encode_bool| + EXPORT |vp8_stop_encode| + EXPORT |vp8_encode_value| + + INCLUDE vpx_vp8_enc_asm_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + +; r0 BOOL_CODER *br +; r1 unsigned char *source + +|vp8_start_encode| PROC + mov r12, #0 + mov r3, #255 + mvn r2, #23 + str r12, [r0, #vp8_writer_lowvalue] + str r3, [r0, #vp8_writer_range] + str r12, [r0, #vp8_writer_value] + str r2, [r0, #vp8_writer_count] + str r12, [r0, #vp8_writer_pos] + str r1, [r0, #vp8_writer_buffer] + bx lr + ENDP + +; r0 BOOL_CODER *br +; r1 int bit +; r2 int probability +|vp8_encode_bool| PROC + push {r4-r9, lr} + + mov r4, r2 + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + sub r7, r5, #1 ; range-1 + + cmp r1, #0 + mul r4, r4, r7 ; ((range-1) * probability) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * probability) >> 8) + + addne r2, r2, r4 ; if (bit) lowvalue += split + subne r4, r5, r4 ; if (bit) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r1, [r7, r4] + cmpge r1, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r1, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r1, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r9, pc} + ENDP + +; r0 BOOL_CODER *br +|vp8_stop_encode| PROC + push {r4-r10, lr} + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + mov r10, #32 + +stop_encode_loop + sub r7, r5, #1 ; range-1 + + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_se ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_se + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_se +token_zero_while_loop_se + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_se + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r1, [r7, r4] + cmpge r1, #0xff + beq token_zero_while_loop_se + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_se + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r1, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r1, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_se + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r10, r10, #1 + bne stop_encode_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r10, pc} + + ENDP + +; r0 BOOL_CODER *br +; r1 int data +; r2 int bits +|vp8_encode_value| PROC + push {r4-r11, lr} + + mov r10, r2 + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + + ; reverse the stream of bits to be packed. Normally + ; the most significant bit is peeled off and compared + ; in the form of (v >> --n) & 1. ARM architecture has + ; the ability to set a flag based on the value of the + ; bit shifted off the bottom of the register. To make + ; that happen the bitstream is reversed. + rbit r11, r1 + rsb r4, r10, #32 ; 32-n + + ; v is kept in r1 during the token pack loop + lsr r1, r11, r4 ; v >>= 32 - n + +encode_value_loop + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsrs r1, r1, #1 ; bit = v >> n + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + addcs r2, r2, r4 ; if (bit) lowvalue += split + subcs r4, r5, r4 ; if (bit) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_ev ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_ev + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_ev +token_zero_while_loop_ev + mov r9, #0 + strb r9, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_ev + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop_ev + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r9, [r7, r4] ; w->buffer[x] + add r9, r9, #1 + strb r9, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_ev + rsb r4, r6, #24 ; 24-offset + ldr r9, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r9, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_ev + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r10, r10, #1 + bne encode_value_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + pop {r4-r11, pc} + ENDP + + END
diff --git a/vp8/encoder/arm/neon/fastfdct4x4_neon.asm b/vp8/encoder/arm/neon/fastfdct4x4_neon.asm new file mode 100644 index 0000000..d5dec44 --- /dev/null +++ b/vp8/encoder/arm/neon/fastfdct4x4_neon.asm
@@ -0,0 +1,126 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_fast_fdct4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_fast_fdct4x4_c(short *input, short *output, int pitch); +;NOTE: +;The input *src_diff. src_diff is calculated as: +;diff_ptr[c] = src_ptr[c] - pred_ptr[c]; (in Subtract* function) +;In which *src_ptr and *pred_ptr both are unsigned char. +;Therefore, *src_diff should be in the range of [-255, 255]. +;CAUTION: +;The input values of 25th block are set in vp8_build_dcblock function, which are out of [-255, 255]. +;But, VP8 encoder only uses vp8_short_fdct4x4_c for 25th block, not vp8_fast_fdct4x4_c. That makes +;it ok for assuming *input in [-255, 255] in vp8_fast_fdct4x4_c, but not ok in vp8_short_fdct4x4_c. + +|vp8_fast_fdct4x4_neon| PROC + vld1.16 {d2}, [r0], r2 ;load input + ldr r12, _ffdct_coeff_ + vld1.16 {d3}, [r0], r2 + vld1.16 {d4}, [r0], r2 + vld1.16 {d0}, [r12] + vld1.16 {d5}, [r0], r2 + + ;First for-loop + ;transpose d2, d3, d4, d5. Then, d2=ip[0], d3=ip[1], d4=ip[2], d5=ip[3] + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vadd.s16 d6, d2, d5 ;ip[0]+ip[3] + vadd.s16 d7, d3, d4 ;ip[1]+ip[2] + vsub.s16 d8, d3, d4 ;ip[1]-ip[2] + vsub.s16 d9, d2, d5 ;ip[0]-ip[3] + vshl.i16 q3, q3, #1 ; a1, b1 + vshl.i16 q4, q4, #1 ; c1, d1 + + vadd.s16 d10, d6, d7 ;temp1 = a1 + b1 + vsub.s16 d11, d6, d7 ;temp2 = a1 - b1 + + vqdmulh.s16 q6, q5, d0[1] + vqdmulh.s16 q8, q4, d0[0] + vqdmulh.s16 q7, q4, d0[2] + + vshr.s16 q6, q6, #1 + vshr.s16 q8, q8, #1 + vshr.s16 q7, q7, #1 ;d14:temp1 = ( c1 * x_c3)>>16; d15:temp1 = (d1 * x_c3)>>16 + vadd.s16 q8, q4, q8 ;d16:temp2 = ((c1 * x_c1)>>16) + c1; d17:temp2 = ((d1 * x_c1)>>16) + d1 + + vadd.s16 d2, d10, d12 ;op[0] = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d4, d11, d13 ;op[2] = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d3, d14, d17 ;op[1] = temp1 + temp2 -- q is not necessary, just for protection + vsub.s16 d5, d15, d16 ;op[3] = temp1 - temp2 + + ;Second for-loop + ;transpose d2, d3, d4, d5. Then, d2=ip[0], d3=ip[4], d4=ip[8], d5=ip[12] + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vadd.s16 d6, d2, d5 ;a1 = ip[0]+ip[12] + vadd.s16 d7, d3, d4 ;b1 = ip[4]+ip[8] + vsub.s16 d8, d3, d4 ;c1 = ip[4]-ip[8] + vsub.s16 d9, d2, d5 ;d1 = ip[0]-ip[12] + + vadd.s16 d10, d6, d7 ;temp1 = a1 + b1 + vsub.s16 d11, d6, d7 ;temp2 = a1 - b1 + + + vqdmulh.s16 q6, q5, d0[1] + vqdmulh.s16 q8, q4, d0[0] + vqdmulh.s16 q7, q4, d0[2] + + vshr.s16 q6, q6, #1 + vshr.s16 q8, q8, #1 + vshr.s16 q7, q7, #1 ;d14:temp1 = ( c1 * x_c3)>>16; d15:temp1 = (d1 * x_c3)>>16 + vadd.s16 q8, q4, q8 ;d16:temp2 = ((c1 * x_c1)>>16) + c1; d17:temp2 = ((d1 * x_c1)>>16) + d1 + + vadd.s16 d2, d10, d12 ;a2 = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d4, d11, d13 ;c2 = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d3, d14, d17 ;b2 = temp1 + temp2 -- q is not necessary, just for protection + vsub.s16 d5, d15, d16 ;d2 = temp1 - temp2 + + vclt.s16 q3, q1, #0 + vclt.s16 q4, q2, #0 + + vsub.s16 q1, q1, q3 + vsub.s16 q2, q2, q4 + + vshr.s16 q1, q1, #1 + vshr.s16 q2, q2, #1 + + vst1.16 {q1, q2}, [r1] + + bx lr + + ENDP + +;----------------- + AREA fastfdct_dat, DATA, READONLY +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_ffdct_coeff_ + DCD ffdct_coeff +ffdct_coeff +; 60547 = 0xEC83 +; 46341 = 0xB505 +; 25080 = 0x61F8 + DCD 0xB505EC83, 0x000061F8 + + END
diff --git a/vp8/encoder/arm/neon/fastfdct8x4_neon.asm b/vp8/encoder/arm/neon/fastfdct8x4_neon.asm new file mode 100644 index 0000000..de1c254 --- /dev/null +++ b/vp8/encoder/arm/neon/fastfdct8x4_neon.asm
@@ -0,0 +1,179 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_fast_fdct8x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_fast_fdct4x4_c(short *input, short *output, int pitch); +;NOTE: +;The input *src_diff. src_diff is calculated as: +;diff_ptr[c] = src_ptr[c] - pred_ptr[c]; (in Subtract* function) +;In which *src_ptr and *pred_ptr both are unsigned char. +;Therefore, *src_diff should be in the range of [-255, 255]. +;CAUTION: +;The input values of 25th block are set in vp8_build_dcblock function, which are out of [-255, 255]. +;But, VP8 encoder only uses vp8_short_fdct4x4_c for 25th block, not vp8_fast_fdct4x4_c. That makes +;it ok for assuming *input in [-255, 255] in vp8_fast_fdct4x4_c, but not ok in vp8_short_fdct4x4_c. + +|vp8_fast_fdct8x4_neon| PROC + vld1.16 {q1}, [r0], r2 ;load input + ldr r12, _ffdct8_coeff_ + vld1.16 {q2}, [r0], r2 + vld1.16 {q3}, [r0], r2 + vld1.16 {d0}, [r12] + vld1.16 {q4}, [r0], r2 + + ;First for-loop + ;transpose d2, d4, d6, d8. Then, d2=ip[0], d4=ip[1], d6=ip[2], d8=ip[3] + ;transpose d3, d5, d7, d9. Then, d3=ip[0], d5=ip[1], d7=ip[2], d9=ip[3] + vtrn.32 d2, d6 + vtrn.32 d3, d7 + vtrn.32 d4, d8 + vtrn.32 d5, d9 + vtrn.16 d2, d4 + vtrn.16 d3, d5 + vtrn.16 d6, d8 + vtrn.16 d7, d9 + + vadd.s16 d10, d2, d8 ;ip[0]+ip[3] + vadd.s16 d11, d4, d6 ;ip[1]+ip[2] + vsub.s16 d12, d4, d6 ;ip[1]-ip[2] + vsub.s16 d13, d2, d8 ;ip[0]-ip[3] + vadd.s16 d22, d3, d9 + vadd.s16 d23, d5, d7 + vsub.s16 d24, d5, d7 + vsub.s16 d25, d3, d9 + + vshl.i16 q5, q5, #1 ; a1, b1 + vshl.i16 q6, q6, #1 ; c1, d1 + vshl.i16 q1, q11, #1 + vshl.i16 q2, q12, #1 + + vadd.s16 d14, d10, d11 ;temp1 = a1 + b1 + vsub.s16 d15, d10, d11 ;temp2 = a1 - b1 + vadd.s16 d24, d2, d3 + vsub.s16 d25, d2, d3 + + vqdmulh.s16 q8, q7, d0[1] + vqdmulh.s16 q13, q12, d0[1] + vqdmulh.s16 q10, q6, d0[0] + vqdmulh.s16 q15, q2, d0[0] + vqdmulh.s16 q9, q6, d0[2] + vqdmulh.s16 q14, q2, d0[2] + + vshr.s16 q8, q8, #1 + vshr.s16 q13, q13, #1 + vshr.s16 q10, q10, #1 + vshr.s16 q15, q15, #1 + vshr.s16 q9, q9, #1 ;d18:temp1 = ( c1 * x_c3)>>16; d19:temp1 = (d1 * x_c3)>>16 + vshr.s16 q14, q14, #1 ;d28:temp1 = ( c1 * x_c3)>>16; d29:temp1 = (d1 * x_c3)>>16 + vadd.s16 q10, q6, q10 ;d20:temp2 = ((c1 * x_c1)>>16) + c1; d21:temp2 = ((d1 * x_c1)>>16) + d1 + vadd.s16 q15, q2, q15 ;d30:temp2 = ((c1 * x_c1)>>16) + c1; d31:temp2 = ((d1 * x_c1)>>16) + d1 + + vadd.s16 d2, d14, d16 ;op[0] = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d3, d24, d26 ;op[0] = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d6, d15, d17 ;op[2] = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d7, d25, d27 ;op[2] = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d4, d18, d21 ;op[1] = temp1 + temp2 -- q is not necessary, just for protection + vadd.s16 d5, d28, d31 ;op[1] = temp1 + temp2 -- q is not necessary, just for protection + vsub.s16 d8, d19, d20 ;op[3] = temp1 - temp2 + vsub.s16 d9, d29, d30 ;op[3] = temp1 - temp2 + + ;Second for-loop + ;transpose d2, d4, d6, d8. Then, d2=ip[0], d4=ip[4], d6=ip[8], d8=ip[12] + ;transpose d3, d5, d7, d9. Then, d3=ip[0], d5=ip[4], d7=ip[8], d9=ip[12] + vtrn.32 d2, d6 + vtrn.32 d3, d7 + vtrn.32 d4, d8 + vtrn.32 d5, d9 + vtrn.16 d2, d4 + vtrn.16 d3, d5 + vtrn.16 d6, d8 + vtrn.16 d7, d9 + + vadd.s16 d10, d2, d8 ;a1 = ip[0]+ip[12] + vadd.s16 d11, d4, d6 ;b1 = ip[4]+ip[8] + vsub.s16 d12, d4, d6 ;c1 = ip[4]-ip[8] + vsub.s16 d13, d2, d8 ;d1 = ip[0]-ip[12] + vadd.s16 d2, d3, d9 + vadd.s16 d4, d5, d7 + vsub.s16 d24, d5, d7 + vsub.s16 d25, d3, d9 + + vadd.s16 d14, d10, d11 ;temp1 = a1 + b1 + vsub.s16 d15, d10, d11 ;temp2 = a1 - b1 + vadd.s16 d22, d2, d4 + vsub.s16 d23, d2, d4 + + vqdmulh.s16 q8, q7, d0[1] + vqdmulh.s16 q13, q11, d0[1] + vqdmulh.s16 q10, q6, d0[0] + vqdmulh.s16 q15, q12, d0[0] + vqdmulh.s16 q9, q6, d0[2] + vqdmulh.s16 q14, q12, d0[2] + + vshr.s16 q8, q8, #1 + vshr.s16 q13, q13, #1 + vshr.s16 q10, q10, #1 + vshr.s16 q15, q15, #1 + vshr.s16 q9, q9, #1 ;d18:temp1 = ( c1 * x_c3)>>16; d19:temp1 = (d1 * x_c3)>>16 + vshr.s16 q14, q14, #1 ;d28:temp1 = ( c1 * x_c3)>>16; d29:temp1 = (d1 * x_c3)>>16 + vadd.s16 q10, q6, q10 ;d20:temp2 = ((c1 * x_c1)>>16) + c1; d21:temp2 = ((d1 * x_c1)>>16) + d1 + vadd.s16 q15, q12, q15 ;d30:temp2 = ((c1 * x_c1)>>16) + c1; d31:temp2 = ((d1 * x_c1)>>16) + d1 + + vadd.s16 d2, d14, d16 ;a2 = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d6, d22, d26 ;a2 = ((temp1 * x_c2 )>>16) + temp1 + vadd.s16 d4, d15, d17 ;c2 = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d8, d23, d27 ;c2 = ((temp2 * x_c2 )>>16) + temp2 + vadd.s16 d3, d18, d21 ;b2 = temp1 + temp2 -- q is not necessary, just for protection + vadd.s16 d7, d28, d31 ;b2 = temp1 + temp2 -- q is not necessary, just for protection + vsub.s16 d5, d19, d20 ;d2 = temp1 - temp2 + vsub.s16 d9, d29, d30 ;d2 = temp1 - temp2 + + vclt.s16 q5, q1, #0 + vclt.s16 q6, q2, #0 + vclt.s16 q7, q3, #0 + vclt.s16 q8, q4, #0 + + vsub.s16 q1, q1, q5 + vsub.s16 q2, q2, q6 + vsub.s16 q3, q3, q7 + vsub.s16 q4, q4, q8 + + vshr.s16 q1, q1, #1 + vshr.s16 q2, q2, #1 + vshr.s16 q3, q3, #1 + vshr.s16 q4, q4, #1 + + vst1.16 {q1, q2}, [r1]! + vst1.16 {q3, q4}, [r1] + + bx lr + + ENDP + +;----------------- + AREA fastfdct8x4_dat, DATA, READONLY +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_ffdct8_coeff_ + DCD ffdct8_coeff +ffdct8_coeff +; 60547 = 0xEC83 +; 46341 = 0xB505 +; 25080 = 0x61F8 + DCD 0xB505EC83, 0x000061F8 + + END
diff --git a/vp8/encoder/arm/neon/fastquantizeb_neon.asm b/vp8/encoder/arm/neon/fastquantizeb_neon.asm new file mode 100644 index 0000000..1107037 --- /dev/null +++ b/vp8/encoder/arm/neon/fastquantizeb_neon.asm
@@ -0,0 +1,117 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_fast_quantize_b_neon_func| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 short *coeff_ptr +; r1 short *zbin_ptr +; r2 short *qcoeff_ptr +; r3 short *dqcoeff_ptr +; stack short *dequant_ptr +; stack short *scan_mask +; stack short *round_ptr +; stack short *quant_ptr + +; return int * eob +|vp8_fast_quantize_b_neon_func| PROC + vld1.16 {q0, q1}, [r0] ;load z + vld1.16 {q10, q11}, [r1] ;load zbin + + vabs.s16 q4, q0 ;calculate x = abs(z) + vabs.s16 q5, q1 + + vcge.s16 q10, q4, q10 ;x>=zbin + vcge.s16 q11, q5, q11 + + ;if x<zbin (q10 & q11 are all 0), go to zero_output + vorr.s16 q6, q10, q11 + vorr.s16 d12, d12, d13 + vmov r0, r1, d12 + orr r0, r0, r1 + cmp r0, #0 + beq zero_output + + ldr r0, [sp, #8] ;load round_ptr + ldr r12, [sp, #12] ;load quant_ptr + + ;right shift 15 to get sign, all 0 if it is positive, all 1 if it is negative + vshr.s16 q2, q0, #15 ; sz + vshr.s16 q3, q1, #15 + + vld1.s16 {q6, q7}, [r0] ;load round_ptr [0-15] + vld1.s16 {q8, q9}, [r12] ;load quant_ptr [0-15] + + vadd.s16 q4, q6 ;x + Round + vadd.s16 q5, q7 + + ldr r0, [sp, #4] ;load rvsplus1_scan_order ptr + + vqdmulh.s16 q4, q8 ;y = ((Round + abs(z)) * Quant) >> 16 + vqdmulh.s16 q5, q9 + + vld1.16 {q0, q1}, [r0] ;load rvsplus1_scan_order + vceq.s16 q8, q8 ;set q8 to all 1 + + vshr.s16 q4, #1 ;right shift 1 after vqdmulh + vshr.s16 q5, #1 + + ;modify data to have its original sign + veor.s16 q4, q2 ; y^sz + veor.s16 q5, q3 + + ldr r12, [sp] ;load dequant_ptr + + vsub.s16 q4, q2 ; x1 = (y^sz) - sz = (y^sz) - (-1) (two's complement) + vsub.s16 q5, q3 + + vand.s16 q4, q10 ;mask off x1 elements + vand.s16 q5, q11 + + vld1.s16 {q6, q7}, [r12] ;load dequant_ptr[i] + + vtst.16 q14, q4, q8 ;now find eob + vtst.16 q15, q5, q8 ;non-zero element is set to all 1 in q4, q5 + + vst1.s16 {q4, q5}, [r2] ;store: qcoeff = x1 + + vand q0, q0, q14 ;get all valid number from rvsplus1_scan_order array + vand q1, q1, q15 + + vmax.u16 q0, q0, q1 ;find maximum value in q0, q1 + vmax.u16 d0, d0, d1 + vmovl.u16 q0, d0 + + vmul.s16 q6, q4 ;x * Dequant + vmul.s16 q7, q5 + + vmax.u32 d0, d0, d1 + vpmax.u32 d0, d0, d0 + + vst1.s16 {q6, q7}, [r3] ;store dqcoeff = x * Dequant + + vmov.32 r0, d0[0] + bx lr + +zero_output + vst1.s16 {q10, q11}, [r2] ; qcoeff = 0 + vst1.s16 {q10, q11}, [r3] ; dqcoeff = 0 + mov r0, #0 + + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/sad16_neon.asm b/vp8/encoder/arm/neon/sad16_neon.asm new file mode 100644 index 0000000..6169f10 --- /dev/null +++ b/vp8/encoder/arm/neon/sad16_neon.asm
@@ -0,0 +1,206 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sad16x16_neon| + EXPORT |vp8_sad16x8_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int src_stride +; r2 unsigned char *ref_ptr +; r3 int ref_stride +|vp8_sad16x16_neon| PROC +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabdl.u8 q12, d0, d8 + vabdl.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + +;; + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0] + vld1.8 {q7}, [r2] + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vadd.u16 q0, q12, q13 + + vpaddl.u16 q1, q0 + vpaddl.u32 q0, q1 + + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;============================== +;unsigned int vp8_sad16x8_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +|vp8_sad16x8_neon| PROC + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabdl.u8 q12, d0, d8 + vabdl.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vld1.8 {q0}, [r0], r1 + vld1.8 {q4}, [r2], r3 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vld1.8 {q1}, [r0], r1 + vld1.8 {q5}, [r2], r3 + + vabal.u8 q12, d0, d8 + vabal.u8 q13, d1, d9 + + vld1.8 {q2}, [r0], r1 + vld1.8 {q6}, [r2], r3 + + vabal.u8 q12, d2, d10 + vabal.u8 q13, d3, d11 + + vld1.8 {q3}, [r0], r1 + vld1.8 {q7}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q13, d5, d13 + + vabal.u8 q12, d6, d14 + vabal.u8 q13, d7, d15 + + vadd.u16 q0, q12, q13 + + vpaddl.u16 q1, q0 + vpaddl.u32 q0, q1 + + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/sad8_neon.asm b/vp8/encoder/arm/neon/sad8_neon.asm new file mode 100644 index 0000000..28604dd --- /dev/null +++ b/vp8/encoder/arm/neon/sad8_neon.asm
@@ -0,0 +1,208 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sad8x8_neon| + EXPORT |vp8_sad8x16_neon| + EXPORT |vp8_sad4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; unsigned int vp8_sad8x8_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad8x8_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 q1, q12 + vpaddl.u32 q0, q1 + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;============================ +;unsigned int vp8_sad8x16_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad8x16_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vabal.u8 q12, d6, d14 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabal.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 q1, q12 + vpaddl.u32 q0, q1 + vadd.u32 d0, d0, d1 + + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;=========================== +;unsigned int vp8_sad4x4_c( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) + +|vp8_sad4x4_neon| PROC + vld1.8 {d0}, [r0], r1 + vld1.8 {d8}, [r2], r3 + + vld1.8 {d2}, [r0], r1 + vld1.8 {d10}, [r2], r3 + + vabdl.u8 q12, d0, d8 + + vld1.8 {d4}, [r0], r1 + vld1.8 {d12}, [r2], r3 + + vabal.u8 q12, d2, d10 + + vld1.8 {d6}, [r0], r1 + vld1.8 {d14}, [r2], r3 + + vabal.u8 q12, d4, d12 + vabal.u8 q12, d6, d14 + + vpaddl.u16 d1, d24 + vpaddl.u32 d0, d1 + vmov.32 r0, d0[0] + + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/shortfdct_neon.asm b/vp8/encoder/arm/neon/shortfdct_neon.asm new file mode 100644 index 0000000..26bc0d0 --- /dev/null +++ b/vp8/encoder/arm/neon/shortfdct_neon.asm
@@ -0,0 +1,146 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_short_fdct4x4_neon| + EXPORT |vp8_short_fdct8x4_neon| + ARM + REQUIRE8 + PRESERVE8 + + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 short *input +; r1 short *output +; r2 int pitch +; Input has a pitch, output is contiguous +|vp8_short_fdct4x4_neon| PROC + ldr r12, _dct_matrix_ + vld1.16 d0, [r0], r2 + vld1.16 d1, [r0], r2 + vld1.16 d2, [r0], r2 + vld1.16 d3, [r0] + vld1.16 {q2, q3}, [r12] + +;first stage + vmull.s16 q11, d4, d0[0] ;i=0 + vmull.s16 q12, d4, d1[0] ;i=1 + vmull.s16 q13, d4, d2[0] ;i=2 + vmull.s16 q14, d4, d3[0] ;i=3 + + vmlal.s16 q11, d5, d0[1] + vmlal.s16 q12, d5, d1[1] + vmlal.s16 q13, d5, d2[1] + vmlal.s16 q14, d5, d3[1] + + vmlal.s16 q11, d6, d0[2] + vmlal.s16 q12, d6, d1[2] + vmlal.s16 q13, d6, d2[2] + vmlal.s16 q14, d6, d3[2] + + vmlal.s16 q11, d7, d0[3] ;sumtemp for i=0 + vmlal.s16 q12, d7, d1[3] ;sumtemp for i=1 + vmlal.s16 q13, d7, d2[3] ;sumtemp for i=2 + vmlal.s16 q14, d7, d3[3] ;sumtemp for i=3 + + ; rounding + vrshrn.i32 d22, q11, #14 + vrshrn.i32 d24, q12, #14 + vrshrn.i32 d26, q13, #14 + vrshrn.i32 d28, q14, #14 + +;second stage + vmull.s16 q4, d22, d4[0] ;i=0 + vmull.s16 q5, d22, d4[1] ;i=1 + vmull.s16 q6, d22, d4[2] ;i=2 + vmull.s16 q7, d22, d4[3] ;i=3 + + vmlal.s16 q4, d24, d5[0] + vmlal.s16 q5, d24, d5[1] + vmlal.s16 q6, d24, d5[2] + vmlal.s16 q7, d24, d5[3] + + vmlal.s16 q4, d26, d6[0] + vmlal.s16 q5, d26, d6[1] + vmlal.s16 q6, d26, d6[2] + vmlal.s16 q7, d26, d6[3] + + vmlal.s16 q4, d28, d7[0] ;sumtemp for i=0 + vmlal.s16 q5, d28, d7[1] ;sumtemp for i=1 + vmlal.s16 q6, d28, d7[2] ;sumtemp for i=2 + vmlal.s16 q7, d28, d7[3] ;sumtemp for i=3 + + vrshr.s32 q0, q4, #16 + vrshr.s32 q1, q5, #16 + vrshr.s32 q2, q6, #16 + vrshr.s32 q3, q7, #16 + + vmovn.i32 d0, q0 + vmovn.i32 d1, q1 + vmovn.i32 d2, q2 + vmovn.i32 d3, q3 + + vst1.16 {q0, q1}, [r1] + + bx lr + + ENDP + +; r0 short *input +; r1 short *output +; r2 int pitch +|vp8_short_fdct8x4_neon| PROC + ; Store link register and input before calling + ; first 4x4 fdct. Do not need to worry about + ; output or pitch because those pointers are not + ; touched in the 4x4 fdct function + stmdb sp!, {r0, lr} + + bl vp8_short_fdct4x4_neon + + ldmia sp!, {r0, lr} + + ; Move to the next block of data. + add r0, r0, #8 + add r1, r1, #32 + + ; Second time through do not store off the + ; link register, just return from the 4x4 fdtc + b vp8_short_fdct4x4_neon + + ; Should never get to this. + bx lr + + ENDP + +;----------------- + AREA dct4x4_dat, DATA, READONLY +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_dct_matrix_ + DCD dct_matrix +dct_matrix +; DCW 23170, 30274, 23170, 12540 +; DCW 23170, 12540, -23170,-30274 +; DCW 23170, -12540, -23170, 30274 +; DCW 23170, -30274, 23170,-12540 +; 23170 = 0x5a82 +; -23170 = 0xa57e +; 30274 = 0x7642 +; -30274 = 0x89be +; 12540 = 0x30fc +; -12540 = 0xcf04 + DCD 0x76425a82, 0x30fc5a82 + DCD 0x30fc5a82, 0x89bea57e + DCD 0xcf045a82, 0x7642a57e + DCD 0x89be5a82, 0xcf045a82 + + END
diff --git a/vp8/encoder/arm/neon/subtract_neon.asm b/vp8/encoder/arm/neon/subtract_neon.asm new file mode 100644 index 0000000..8781ca0 --- /dev/null +++ b/vp8/encoder/arm/neon/subtract_neon.asm
@@ -0,0 +1,171 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_subtract_b_neon_func| + EXPORT |vp8_subtract_mby_neon| + EXPORT |vp8_subtract_mbuv_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;========================================= +;void vp8_subtract_b_neon_func(short *diff, unsigned char *src, unsigned char *pred, int stride, int pitch); +|vp8_subtract_b_neon_func| PROC + ldr r12, [sp] ;load pitch + + vld1.8 {d0}, [r1], r3 ;load src + vld1.8 {d1}, [r2], r12 ;load pred + vld1.8 {d2}, [r1], r3 + vld1.8 {d3}, [r2], r12 + vld1.8 {d4}, [r1], r3 + vld1.8 {d5}, [r2], r12 + vld1.8 {d6}, [r1], r3 + vld1.8 {d7}, [r2], r12 + + vsubl.u8 q10, d0, d1 + vsubl.u8 q11, d2, d3 + vsubl.u8 q12, d4, d5 + vsubl.u8 q13, d6, d7 + + mov r12, r12, lsl #1 + + vst1.16 {d20}, [r0], r12 ;store diff + vst1.16 {d22}, [r0], r12 + vst1.16 {d24}, [r0], r12 + vst1.16 {d26}, [r0], r12 + + bx lr + ENDP + +;========================================== +;void vp8_subtract_mby_neon(short *diff, unsigned char *src, unsigned char *pred, int stride) +|vp8_subtract_mby_neon| PROC + mov r12, #4 + +subtract_mby_loop + vld1.8 {q0}, [r1], r3 ;load src + vld1.8 {q1}, [r2]! ;load pred + vld1.8 {q2}, [r1], r3 + vld1.8 {q3}, [r2]! + vld1.8 {q4}, [r1], r3 + vld1.8 {q5}, [r2]! + vld1.8 {q6}, [r1], r3 + vld1.8 {q7}, [r2]! + + vsubl.u8 q8, d0, d2 + vsubl.u8 q9, d1, d3 + vsubl.u8 q10, d4, d6 + vsubl.u8 q11, d5, d7 + vsubl.u8 q12, d8, d10 + vsubl.u8 q13, d9, d11 + vsubl.u8 q14, d12, d14 + vsubl.u8 q15, d13, d15 + + vst1.16 {q8}, [r0]! ;store diff + vst1.16 {q9}, [r0]! + vst1.16 {q10}, [r0]! + vst1.16 {q11}, [r0]! + vst1.16 {q12}, [r0]! + vst1.16 {q13}, [r0]! + vst1.16 {q14}, [r0]! + vst1.16 {q15}, [r0]! + + subs r12, r12, #1 + bne subtract_mby_loop + + bx lr + ENDP + +;================================= +;void vp8_subtract_mbuv_neon(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride) +|vp8_subtract_mbuv_neon| PROC + ldr r12, [sp] + +;u + add r0, r0, #512 ; short *udiff = diff + 256; + add r3, r3, #256 ; unsigned char *upred = pred + 256; + + vld1.8 {d0}, [r1], r12 ;load src + vld1.8 {d1}, [r3]! ;load pred + vld1.8 {d2}, [r1], r12 + vld1.8 {d3}, [r3]! + vld1.8 {d4}, [r1], r12 + vld1.8 {d5}, [r3]! + vld1.8 {d6}, [r1], r12 + vld1.8 {d7}, [r3]! + vld1.8 {d8}, [r1], r12 + vld1.8 {d9}, [r3]! + vld1.8 {d10}, [r1], r12 + vld1.8 {d11}, [r3]! + vld1.8 {d12}, [r1], r12 + vld1.8 {d13}, [r3]! + vld1.8 {d14}, [r1], r12 + vld1.8 {d15}, [r3]! + + vsubl.u8 q8, d0, d1 + vsubl.u8 q9, d2, d3 + vsubl.u8 q10, d4, d5 + vsubl.u8 q11, d6, d7 + vsubl.u8 q12, d8, d9 + vsubl.u8 q13, d10, d11 + vsubl.u8 q14, d12, d13 + vsubl.u8 q15, d14, d15 + + vst1.16 {q8}, [r0]! ;store diff + vst1.16 {q9}, [r0]! + vst1.16 {q10}, [r0]! + vst1.16 {q11}, [r0]! + vst1.16 {q12}, [r0]! + vst1.16 {q13}, [r0]! + vst1.16 {q14}, [r0]! + vst1.16 {q15}, [r0]! + +;v + vld1.8 {d0}, [r2], r12 ;load src + vld1.8 {d1}, [r3]! ;load pred + vld1.8 {d2}, [r2], r12 + vld1.8 {d3}, [r3]! + vld1.8 {d4}, [r2], r12 + vld1.8 {d5}, [r3]! + vld1.8 {d6}, [r2], r12 + vld1.8 {d7}, [r3]! + vld1.8 {d8}, [r2], r12 + vld1.8 {d9}, [r3]! + vld1.8 {d10}, [r2], r12 + vld1.8 {d11}, [r3]! + vld1.8 {d12}, [r2], r12 + vld1.8 {d13}, [r3]! + vld1.8 {d14}, [r2], r12 + vld1.8 {d15}, [r3]! + + vsubl.u8 q8, d0, d1 + vsubl.u8 q9, d2, d3 + vsubl.u8 q10, d4, d5 + vsubl.u8 q11, d6, d7 + vsubl.u8 q12, d8, d9 + vsubl.u8 q13, d10, d11 + vsubl.u8 q14, d12, d13 + vsubl.u8 q15, d14, d15 + + vst1.16 {q8}, [r0]! ;store diff + vst1.16 {q9}, [r0]! + vst1.16 {q10}, [r0]! + vst1.16 {q11}, [r0]! + vst1.16 {q12}, [r0]! + vst1.16 {q13}, [r0]! + vst1.16 {q14}, [r0]! + vst1.16 {q15}, [r0]! + + bx lr + ENDP + + END
diff --git a/vp8/encoder/arm/neon/variance_neon.asm b/vp8/encoder/arm/neon/variance_neon.asm new file mode 100644 index 0000000..64b83ca --- /dev/null +++ b/vp8/encoder/arm/neon/variance_neon.asm
@@ -0,0 +1,275 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_variance16x16_neon| + EXPORT |vp8_variance16x8_neon| + EXPORT |vp8_variance8x16_neon| + EXPORT |vp8_variance8x8_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance16x16_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #8 + +variance16x16_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + ;VPADAL adds adjacent pairs of elements of a vector, and accumulates + ;the results into the elements of the destination vector. The explanation + ;in ARM guide is wrong. + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance16x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + ;vmov.32 r0, d0[0] ;this instruction costs a lot + ;vmov.32 r1, d1[0] + ;mul r0, r0, r0 + ;str r1, [r12] + ;sub r0, r1, r0, asr #8 + + ;sum is in [-255x256, 255x256]. sumxsum is 32-bit. Shift to right should + ;have sign-bit exension, which is vshr.s. Have to use s32 to make it right. + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================ +;unsigned int vp8_variance16x8_c( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *sse) +|vp8_variance16x8_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #4 + +variance16x8_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance16x8_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.s32 d10, d10, #7 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================= +;unsigned int vp8_variance8x16_c( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *sse) + +|vp8_variance8x16_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #8 + +variance8x16_neon_loop + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d2, d6 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + + bne variance8x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.s32 d10, d10, #7 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + +;================================== +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +|vp8_variance8x8_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #2 + +variance8x8_neon_loop + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d1}, [r0], r1 + vld1.8 {d5}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + vld1.8 {d3}, [r0], r1 + vld1.8 {d7}, [r2], r3 + + vsubl.u8 q11, d0, d4 ;calculate diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;calculate sum + vmlal.s16 q9, d22, d22 ;calculate sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne variance8x8_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + ldr r12, [sp] ;load *sse from stack + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r12] ;store sse + vshr.s32 d10, d10, #6 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_memcpy_neon.asm b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm new file mode 100644 index 0000000..f26b4d7 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm
@@ -0,0 +1,67 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_memcpy_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;========================================= +;void vp8_memcpy_neon(unsigned char *dst_ptr, unsigned char *src_ptr, int sz); +|vp8_memcpy_neon| PROC + ;pld [r1] ;preload pred data + ;pld [r1, #128] + ;pld [r1, #256] + ;pld [r1, #384] + + mov r12, r2, lsr #8 ;copy 256 bytes data at one time + +memcpy_neon_loop + vld1.8 {q0, q1}, [r1]! ;load src data + subs r12, r12, #1 + vld1.8 {q2, q3}, [r1]! + vst1.8 {q0, q1}, [r0]! ;copy to dst_ptr + vld1.8 {q4, q5}, [r1]! + vst1.8 {q2, q3}, [r0]! + vld1.8 {q6, q7}, [r1]! + vst1.8 {q4, q5}, [r0]! + vld1.8 {q8, q9}, [r1]! + vst1.8 {q6, q7}, [r0]! + vld1.8 {q10, q11}, [r1]! + vst1.8 {q8, q9}, [r0]! + vld1.8 {q12, q13}, [r1]! + vst1.8 {q10, q11}, [r0]! + vld1.8 {q14, q15}, [r1]! + vst1.8 {q12, q13}, [r0]! + vst1.8 {q14, q15}, [r0]! + + ;pld [r1] ;preload pred data -- need to adjust for real device + ;pld [r1, #128] + ;pld [r1, #256] + ;pld [r1, #384] + + bne memcpy_neon_loop + + ands r3, r2, #0xff ;extra copy + beq done_copy_neon_loop + +extra_copy_neon_loop + vld1.8 {q0}, [r1]! ;load src data + subs r3, r3, #16 + vst1.8 {q0}, [r0]! + bne extra_copy_neon_loop + +done_copy_neon_loop + bx lr + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm new file mode 100644 index 0000000..f535967 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm
@@ -0,0 +1,172 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_mse16x16_neon| + EXPORT |vp8_get16x16pred_error_neon| + EXPORT |vp8_get4x4sse_cs_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;============================ +; r0 unsigned char *src_ptr +; r1 int source_stride +; r2 unsigned char *ref_ptr +; r3 int recon_stride +; stack unsigned int *sse +;note: in this function, sum is never used. So, we can remove this part of calculation +;from vp8_variance(). + +|vp8_mse16x16_neon| PROC + vmov.i8 q7, #0 ;q7, q8, q9, q10 - sse + vmov.i8 q8, #0 + vmov.i8 q9, #0 + vmov.i8 q10, #0 + + mov r12, #8 + +mse16x16_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vmlal.s16 q7, d22, d22 + vmlal.s16 q8, d23, d23 + + subs r12, r12, #1 + + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vmlal.s16 q7, d26, d26 + vmlal.s16 q8, d27, d27 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne mse16x16_neon_loop + + vadd.u32 q7, q7, q8 + vadd.u32 q9, q9, q10 + + ldr r12, [sp] ;load *sse from stack + + vadd.u32 q10, q7, q9 + vpaddl.u32 q1, q10 + vadd.u64 d0, d2, d3 + + vst1.32 {d0[0]}, [r12] + vmov.32 r0, d0[0] + + bx lr + + ENDP + +;============================ +; r0 unsigned char *src_ptr +; r1 int src_stride +; r2 unsigned char *ref_ptr +; r3 int ref_stride +|vp8_get16x16pred_error_neon| PROC + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - pred_error + vmov.i8 q10, #0 + + mov r12, #8 + +get16x16pred_error_neon_loop + vld1.8 {q0}, [r0], r1 ;Load up source and reference + vld1.8 {q2}, [r2], r3 + vld1.8 {q1}, [r0], r1 + vld1.8 {q3}, [r2], r3 + + vsubl.u8 q11, d0, d4 + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 + vmlal.s16 q9, d22, d22 + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne get16x16pred_error_neon_loop + + vadd.u32 q10, q9, q10 + vpaddl.s32 q0, q8 + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] + bx lr + + ENDP + +;============================= +; r0 unsigned char *src_ptr, +; r1 int source_stride, +; r2 unsigned char *ref_ptr, +; r3 int recon_stride +|vp8_get4x4sse_cs_neon| PROC + vld1.8 {d0}, [r0], r1 ;Load up source and reference + vld1.8 {d4}, [r2], r3 + vld1.8 {d1}, [r0], r1 + vld1.8 {d5}, [r2], r3 + vld1.8 {d2}, [r0], r1 + vld1.8 {d6}, [r2], r3 + vld1.8 {d3}, [r0], r1 + vld1.8 {d7}, [r2], r3 + + vsubl.u8 q11, d0, d4 + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vmull.s16 q7, d22, d22 + vmull.s16 q8, d24, d24 + vmull.s16 q9, d26, d26 + vmull.s16 q10, d28, d28 + + vadd.u32 q7, q7, q8 + vadd.u32 q9, q9, q10 + vadd.u32 q9, q7, q9 + + vpaddl.u32 q1, q9 + vadd.u64 d0, d2, d3 + + vmov.32 r0, d0[0] + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_packtokens_armv7.asm b/vp8/encoder/arm/neon/vp8_packtokens_armv7.asm new file mode 100644 index 0000000..9c52c52 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_packtokens_armv7.asm
@@ -0,0 +1,300 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_tokens_armv7| + + INCLUDE vpx_vp8_enc_asm_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + +; r0 vp8_writer *w +; r1 const TOKENEXTRA *p +; r2 int xcount +; r3 vp8_coef_encodings +; s0 vp8_extra_bits +; s1 vp8_coef_tree +|vp8cx_pack_tokens_armv7| PROC + push {r4-r11, lr} + + ; Add size of xcount * sizeof (TOKENEXTRA) to get stop + ; sizeof (TOKENEXTRA) is 20 + add r2, r2, r2, lsl #2 ; xcount + sub sp, sp, #12 + add r2, r1, r2, lsl #2 ; stop = p + xcount + str r2, [sp, #0] + str r3, [sp, #8] ; save vp8_coef_encodings + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + b check_p_lt_stop + +while_p_lt_stop + ldr r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #8] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldr r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + ; reverse the stream of bits to be packed. Normally + ; the most significant bit is peeled off and compared + ; in the form of (v >> --n) & 1. ARM architecture has + ; the ability to set a flag based on the value of the + ; bit shifted off the bottom of the register. To make + ; that happen the bitstream is reversed. + rbit r12, r6 + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #52] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsr r12, r12, r4 ; v >>= 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsrs r12, r12, #1 ; bb = v >> n + mul r4, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #52] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldr r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #48] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 20 + add r6, r6, r6, lsl #2 ; b = vp8_extra_bits + t + add r12, r7, r6, lsl #2 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldr lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rbit r12, r7 ; reverse v + rsb r4, r8, #32 + lsr r12, r12, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsrs r12, r12, #1 ; v >> n + mul r4, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r4, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #0x10] + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + add sp, sp, #12 + pop {r4-r11, pc} + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_packtokens_mbrow_armv7.asm b/vp8/encoder/arm/neon/vp8_packtokens_mbrow_armv7.asm new file mode 100644 index 0000000..92b0989 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_packtokens_mbrow_armv7.asm
@@ -0,0 +1,335 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_mb_row_tokens_armv7| + + INCLUDE vpx_vp8_enc_asm_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + +; r0 VP8_COMP *cpi +; r1 vp8_writer *w +; r2 vp8_coef_encodings +; r3 vp8_extra_bits +; s0 vp8_coef_tree + +|vp8cx_pack_mb_row_tokens_armv7| PROC + push {r4-r11, lr} + sub sp, sp, #24 + + ; Compute address of cpi->common.mb_rows + ldr r4, _VP8_COMP_common_ + ldr r6, _VP8_COMMON_MBrows_ + add r4, r0, r4 + + ldr r5, [r4, r6] ; load up mb_rows + + str r2, [sp, #20] ; save vp8_coef_encodings + str r5, [sp, #12] ; save mb_rows + str r3, [sp, #8] ; save vp8_extra_bits + + ldr r4, _VP8_COMP_tplist_ + add r4, r0, r4 + ldr r7, [r4, #0] ; dereference cpi->tp_list + + mov r0, r1 ; keep same as other loops + + ldr r2, [r0, #vp8_writer_lowvalue] + ldr r5, [r0, #vp8_writer_range] + ldr r3, [r0, #vp8_writer_count] + +mb_row_loop + + ldr r1, [r7, #tokenlist_start] + ldr r9, [r7, #tokenlist_stop] + str r9, [sp, #0] ; save stop for later comparison + str r7, [sp, #16] ; tokenlist address for next time + + b check_p_lt_stop + + ; actuall work gets done here! + +while_p_lt_stop + ldr r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #20] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldr r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + ; reverse the stream of bits to be packed. Normally + ; the most significant bit is peeled off and compared + ; in the form of (v >> --n) & 1. ARM architecture has + ; the ability to set a flag based on the value of the + ; bit shifted off the bottom of the register. To make + ; that happen the bitstream is reversed. + rbit r12, r6 + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #60] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsr r12, r12, r4 ; v >>= 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsrs r12, r12, #1 ; bb = v >> n + mul r4, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #60] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldr r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #8] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 20 + add r6, r6, r6, lsl #2 ; b = vp8_extra_bits + t + add r12, r7, r6, lsl #2 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldr lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rbit r12, r7 ; reverse v + rsb r4, r8, #32 + lsr r12, r12, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsrs r12, r12, #1 ; v >> n + mul r4, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r4, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #0x10] + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + ldr r6, [sp, #12] ; mb_rows + ldr r7, [sp, #16] ; tokenlist address + subs r6, r6, #1 + add r7, r7, #TOKENLIST_SZ ; next element in the array + str r6, [sp, #12] + bne mb_row_loop + + str r2, [r0, #vp8_writer_lowvalue] + str r5, [r0, #vp8_writer_range] + str r3, [r0, #vp8_writer_count] + add sp, sp, #24 + pop {r4-r11, pc} + ENDP + +_VP8_COMP_common_ + DCD vp8_comp_common +_VP8_COMMON_MBrows_ + DCD vp8_common_mb_rows +_VP8_COMP_tplist_ + DCD vp8_comp_tplist + + END
diff --git a/vp8/encoder/arm/neon/vp8_packtokens_partitions_armv7.asm b/vp8/encoder/arm/neon/vp8_packtokens_partitions_armv7.asm new file mode 100644 index 0000000..6d5f882 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_packtokens_partitions_armv7.asm
@@ -0,0 +1,471 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8cx_pack_tokens_into_partitions_armv7| + + INCLUDE vpx_vp8_enc_asm_offsets.asm + + ARM + REQUIRE8 + PRESERVE8 + + AREA |.text|, CODE, READONLY + +; r0 VP8_COMP *cpi +; r1 unsigned char *cx_data +; r2 int num_part +; r3 *size +; s0 vp8_coef_encodings +; s1 vp8_extra_bits, +; s2 const vp8_tree_index *, + +|vp8cx_pack_tokens_into_partitions_armv7| PROC + push {r4-r11, lr} + sub sp, sp, #44 + + ; Compute address of cpi->common.mb_rows + ldr r4, _VP8_COMP_common_ + ldr r6, _VP8_COMMON_MBrows_ + add r4, r0, r4 + + ldr r5, [r4, r6] ; load up mb_rows + + str r5, [sp, #36] ; save mb_rows + str r1, [sp, #24] ; save cx_data + str r2, [sp, #20] ; save num_part + str r3, [sp, #8] ; save *size + + ; *size = 3*(num_part -1 ); + sub r2, r2, #1 ; num_part - 1 + add r2, r2, r2, lsl #1 ; 3*(num_part - 1) + str r2, [r3] + + add r2, r2, r1 ; cx_data + *size + str r2, [sp, #40] ; ptr + + ldr r4, _VP8_COMP_tplist_ + add r4, r0, r4 + ldr r7, [r4, #0] ; dereference cpi->tp_list + str r7, [sp, #32] ; store start of cpi->tp_list + + ldr r11, _VP8_COMP_bc2_ ; load up vp8_writer out of cpi + add r0, r0, r11 + + mov r11, #0 + str r11, [sp, #28] ; i + +numparts_loop + ldr r10, [sp, #40] ; ptr + ldr r5, [sp, #36] ; move mb_rows to the counting section + str r5, [sp, #12] + + ; Reset all of the VP8 Writer data for each partition that + ; is processed. + ; start_encode + mov r2, #0 ; vp8_writer_lowvalue + mov r5, #255 ; vp8_writer_range + mvn r3, #23 ; vp8_writer_count + + str r2, [r0, #vp8_writer_value] + str r2, [r0, #vp8_writer_pos] + str r10, [r0, #vp8_writer_buffer] + +mb_row_loop + + ldr r1, [r7, #tokenlist_start] + ldr r9, [r7, #tokenlist_stop] + str r9, [sp, #0] ; save stop for later comparison + str r7, [sp, #16] ; tokenlist address for next time + + b check_p_lt_stop + + ; actual work gets done here! + +while_p_lt_stop + ldr r6, [r1, #tokenextra_token] ; t + ldr r4, [sp, #80] ; vp8_coef_encodings + mov lr, #0 + add r4, r4, r6, lsl #3 ; a = vp8_coef_encodings + t + ldr r9, [r1, #tokenextra_context_tree] ; pp + + ldr r7, [r1, #tokenextra_skip_eob_node] + + ldr r6, [r4, #vp8_token_value] ; v + ldr r8, [r4, #vp8_token_len] ; n + + ; vp8 specific skip_eob_node + cmp r7, #0 + movne lr, #2 ; i = 2 + subne r8, r8, #1 ; --n + + ; reverse the stream of bits to be packed. Normally + ; the most significant bit is peeled off and compared + ; in the form of (v >> --n) & 1. ARM architecture has + ; the ability to set a flag based on the value of the + ; bit shifted off the bottom of the register. To make + ; that happen the bitstream is reversed. + rbit r12, r6 + rsb r4, r8, #32 ; 32-n + ldr r10, [sp, #88] ; vp8_coef_tree + + ; v is kept in r12 during the token pack loop + lsr r12, r12, r4 ; v >>= 32 - n + +; loop start +token_loop + ldrb r4, [r9, lr, asr #1] ; pp [i>>1] + sub r7, r5, #1 ; range-1 + + ; Decisions are made based on the bit value shifted + ; off of v, so set a flag here based on this. + ; This value is refered to as "bb" + lsrs r12, r12, #1 ; bb = v >> n + mul r4, r4, r7 ; ((range-1) * pp[i>>1])) + + ; bb can only be 0 or 1. So only execute this statement + ; if bb == 1, otherwise it will act like i + 0 + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = vp8_coef_tree[i+bb] + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start +token_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++] + + ; r10 is used earlier in the loop, but r10 is used as + ; temp variable here. So after r10 is used, reload + ; vp8_coef_tree_dcd into r10 + ldr r10, [sp, #88] ; vp8_coef_tree + +token_count_lt_zero + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r8, r8, #1 ; --n + bne token_loop + + ldr r6, [r1, #tokenextra_token] ; t + ldr r7, [sp, #84] ; vp8_extra_bits + ; Add t * sizeof (vp8_extra_bit_struct) to get the desired + ; element. Here vp8_extra_bit_struct == 20 + add r6, r6, r6, lsl #2 ; b = vp8_extra_bits + t + add r12, r7, r6, lsl #2 ; b = vp8_extra_bits + t + + ldr r4, [r12, #vp8_extra_bit_struct_base_val] + cmp r4, #0 + beq skip_extra_bits + +; if( b->base_val) + ldr r8, [r12, #vp8_extra_bit_struct_len] ; L + ldr lr, [r1, #tokenextra_extra] ; e = p->Extra + cmp r8, #0 ; if( L) + beq no_extra_bits + + ldr r9, [r12, #vp8_extra_bit_struct_prob] + asr r7, lr, #1 ; v=e>>1 + + ldr r10, [r12, #vp8_extra_bit_struct_tree] + str r10, [sp, #4] ; b->tree + + rbit r12, r7 ; reverse v + rsb r4, r8, #32 + lsr r12, r12, r4 + + mov lr, #0 ; i = 0 + +extra_bits_loop + ldrb r4, [r9, lr, asr #1] ; pp[i>>1] + sub r7, r5, #1 ; range-1 + lsrs r12, r12, #1 ; v >> n + mul r4, r4, r7 ; (range-1) * pp[i>>1] + addcs lr, lr, #1 ; i + bb + + mov r7, #1 + ldrsb lr, [r10, lr] ; i = b->tree[i+bb] + add r4, r7, r4, lsr #8 ; split = 1 + (((range-1) * pp[i>>1]) >> 8) + + addcs r2, r2, r4 ; if (bb) lowvalue += split + subcs r4, r5, r4 ; if (bb) range = range-split + + clz r6, r4 + sub r6, r6, #24 + + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi extra_count_lt_zero ; if(count >= 0) + + sub r6, r6, r3 ; offset= shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl extra_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos - 1 + b extra_zero_while_start +extra_zero_while_loop + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +extra_zero_while_start + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq extra_zero_while_loop + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] + add r10, r10, #1 + strb r10, [r7, r4] +extra_high_bit_not_set + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++]=(lowvalue >> (24-offset)) + ldr r10, [sp, #4] ; b->tree +extra_count_lt_zero + lsl r2, r2, r6 + + subs r8, r8, #1 ; --n + bne extra_bits_loop ; while (n) + +no_extra_bits + ldr lr, [r1, #4] ; e = p->Extra + add r4, r5, #1 ; range + 1 + tst lr, #1 + lsr r4, r4, #1 ; split = (range + 1) >> 1 + addne r2, r2, r4 ; lowvalue += split + subne r4, r5, r4 ; range = range-split + tst r2, #0x80000000 ; lowvalue & 0x80000000 + lsl r5, r4, #1 ; range <<= 1 + beq end_high_bit_not_set + + ldr r4, [r0, #vp8_writer_pos] + mov r7, #0 + sub r4, r4, #1 + b end_zero_while_start +end_zero_while_loop + strb r7, [r6, r4] + sub r4, r4, #1 ; x-- +end_zero_while_start + cmp r4, #0 + ldrge r6, [r0, #vp8_writer_buffer] + ldrb r12, [r6, r4] + cmpge r12, #0xff + beq end_zero_while_loop + + ldr r6, [r0, #vp8_writer_buffer] + ldrb r7, [r6, r4] + add r7, r7, #1 + strb r7, [r6, r4] +end_high_bit_not_set + adds r3, r3, #1 ; ++count + lsl r2, r2, #1 ; lowvalue <<= 1 + bne end_count_zero + + ldr r4, [r0, #vp8_writer_pos] + mvn r3, #7 + ldr r7, [r0, #vp8_writer_buffer] + lsr r6, r2, #24 ; lowvalue >> 24 + add r12, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r12, [r0, #0x10] + strb r6, [r7, r4] +end_count_zero +skip_extra_bits + add r1, r1, #TOKENEXTRA_SZ ; ++p +check_p_lt_stop + ldr r4, [sp, #0] ; stop + cmp r1, r4 ; while( p < stop) + bcc while_p_lt_stop + + ldr r10, [sp, #20] ; num_parts + mov r1, #TOKENLIST_SZ + mul r1, r10, r1 + + ldr r6, [sp, #12] ; mb_rows + ldr r7, [sp, #16] ; tokenlist address + subs r6, r6, r10 + add r7, r7, r1 ; next element in the array + str r6, [sp, #12] + bgt mb_row_loop + + mov r12, #32 + +stop_encode_loop + sub r7, r5, #1 ; range-1 + + mov r4, r7, lsl #7 ; ((range-1) * 128) + + mov r7, #1 + add r4, r7, r4, lsr #8 ; 1 + (((range-1) * 128) >> 8) + + ; Counting the leading zeros is used to normalize range. + clz r6, r4 + sub r6, r6, #24 ; shift + + ; Flag is set on the sum of count. This flag is used later + ; to determine if count >= 0 + adds r3, r3, r6 ; count += shift + lsl r5, r4, r6 ; range <<= shift + bmi token_count_lt_zero_se ; if(count >= 0) + + sub r6, r6, r3 ; offset = shift - count + sub r4, r6, #1 ; offset-1 + lsls r4, r2, r4 ; if((lowvalue<<(offset-1)) & 0x80000000 ) + bpl token_high_bit_not_set_se + + ldr r4, [r0, #vp8_writer_pos] ; x + sub r4, r4, #1 ; x = w->pos-1 + b token_zero_while_start_se +token_zero_while_loop_se + mov r10, #0 + strb r10, [r7, r4] ; w->buffer[x] =(unsigned char)0 + sub r4, r4, #1 ; x-- +token_zero_while_start_se + cmp r4, #0 + ldrge r7, [r0, #vp8_writer_buffer] + ldrb r11, [r7, r4] + cmpge r11, #0xff + beq token_zero_while_loop_se + + ldr r7, [r0, #vp8_writer_buffer] + ldrb r10, [r7, r4] ; w->buffer[x] + add r10, r10, #1 + strb r10, [r7, r4] ; w->buffer[x] + 1 +token_high_bit_not_set_se + rsb r4, r6, #24 ; 24-offset + ldr r10, [r0, #vp8_writer_buffer] + lsr r7, r2, r4 ; lowvalue >> (24-offset) + ldr r4, [r0, #vp8_writer_pos] ; w->pos + lsl r2, r2, r6 ; lowvalue <<= offset + mov r6, r3 ; shift = count + add r11, r4, #1 ; w->pos++ + bic r2, r2, #0xff000000 ; lowvalue &= 0xffffff + str r11, [r0, #vp8_writer_pos] + sub r3, r3, #8 ; count -= 8 + strb r7, [r10, r4] ; w->buffer[w->pos++] + +token_count_lt_zero_se + lsl r2, r2, r6 ; lowvalue <<= shift + + subs r12, r12, #1 + bne stop_encode_loop + + ldr r10, [sp, #8] ; *size + ldr r11, [r10] + ldr r4, [r0, #vp8_writer_pos] ; w->pos + add r11, r11, r4 ; *size += w->pos + str r11, [r10] + + ldr r9, [sp, #20] ; num_parts + sub r9, r9, #1 + ldr r10, [sp, #28] ; i + cmp r10, r9 ; if(i<(num_part - 1)) + bge skip_write_partition + + ldr r12, [sp, #40] ; ptr + add r12, r12, r4 ; ptr += w->pos + str r12, [sp, #40] + + ldr r9, [sp, #24] ; cx_data + mov r8, r4, asr #8 + strb r4, [r9, #0] + strb r8, [r9, #1] + mov r4, r4, asr #16 + strb r4, [r9, #2] + + add r9, r9, #3 ; cx_data += 3 + str r9, [sp, #24] + +skip_write_partition + + ldr r11, [sp, #28] ; i + ldr r10, [sp, #20] ; num_parts + + add r11, r11, #1 ; i++ + str r11, [sp, #28] + + ldr r7, [sp, #32] ; cpi->tp_list[i] + mov r1, #TOKENLIST_SZ + add r7, r7, r1 ; next element in cpi->tp_list + str r7, [sp, #32] ; cpi->tp_list[i+1] + + cmp r10, r11 + bgt numparts_loop + + + add sp, sp, #44 + pop {r4-r11, pc} + ENDP + +_VP8_COMP_common_ + DCD vp8_comp_common +_VP8_COMMON_MBrows_ + DCD vp8_common_mb_rows +_VP8_COMP_tplist_ + DCD vp8_comp_tplist +_VP8_COMP_bc2_ + DCD vp8_comp_bc2 + + END
diff --git a/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm b/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm new file mode 100644 index 0000000..5269c0a --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.asm
@@ -0,0 +1,75 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_short_walsh4x4_neon| + + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +;void vp8_short_walsh4x4_c(short *input, short *output, int pitch) + +|vp8_short_walsh4x4_neon| PROC + vld1.16 {d2}, [r0], r2 ;load input + vld1.16 {d3}, [r0], r2 + vld1.16 {d4}, [r0], r2 + vld1.16 {d5}, [r0], r2 + + ;First for-loop + ;transpose d2, d3, d4, d5. Then, d2=ip[0], d3=ip[1], d4=ip[2], d5=ip[3] + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vadd.s16 d6, d2, d5 ;a1 = ip[0]+ip[3] + vadd.s16 d7, d3, d4 ;b1 = ip[1]+ip[2] + vsub.s16 d8, d3, d4 ;c1 = ip[1]-ip[2] + vsub.s16 d9, d2, d5 ;d1 = ip[0]-ip[3] + + vadd.s16 d2, d6, d7 ;op[0] = a1 + b1 + vsub.s16 d4, d6, d7 ;op[2] = a1 - b1 + vadd.s16 d3, d8, d9 ;op[1] = c1 + d1 + vsub.s16 d5, d9, d8 ;op[3] = d1 - c1 + + ;Second for-loop + ;transpose d2, d3, d4, d5. Then, d2=ip[0], d3=ip[4], d4=ip[8], d5=ip[12] + vtrn.32 d2, d4 + vtrn.32 d3, d5 + vtrn.16 d2, d3 + vtrn.16 d4, d5 + + vadd.s16 d6, d2, d5 ;a1 = ip[0]+ip[12] + vadd.s16 d7, d3, d4 ;b1 = ip[4]+ip[8] + vsub.s16 d8, d3, d4 ;c1 = ip[4]-ip[8] + vsub.s16 d9, d2, d5 ;d1 = ip[0]-ip[12] + + vadd.s16 d2, d6, d7 ;a2 = a1 + b1; + vsub.s16 d4, d6, d7 ;c2 = a1 - b1; + vadd.s16 d3, d8, d9 ;b2 = c1 + d1; + vsub.s16 d5, d9, d8 ;d2 = d1 - c1; + + vcgt.s16 q3, q1, #0 + vcgt.s16 q4, q2, #0 + + vsub.s16 q1, q1, q3 + vsub.s16 q2, q2, q4 + + vshr.s16 q1, q1, #1 + vshr.s16 q2, q2, #1 + + vst1.16 {q1, q2}, [r1] + + bx lr + + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_subpixelvariance16x16_neon.asm b/vp8/encoder/arm/neon/vp8_subpixelvariance16x16_neon.asm new file mode 100644 index 0000000..aec716e --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_subpixelvariance16x16_neon.asm
@@ -0,0 +1,427 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sub_pixel_variance16x16_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(r5) int dst_pixels_per_line, +; stack(r6) unsigned int *sse +;note: most of the code is copied from bilinear_predict16x16_neon and vp8_variance16x16_neon. + +|vp8_sub_pixel_variance16x16_neon| PROC + push {r4-r6, lr} + + ldr r12, _BilinearTaps_coeff_ + ldr r4, [sp, #16] ;load *dst_ptr from stack + ldr r5, [sp, #20] ;load dst_pixels_per_line from stack + ldr r6, [sp, #24] ;load *sse from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16_only + + add r2, r12, r2, lsl #3 ;calculate filter location + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + + vld1.s32 {d31}, [r2] ;load first_pass filter + + beq firstpass_bfilter16x16_only + + sub sp, sp, #272 ;reserve space on stack for temporary storage + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + mov lr, sp + vld1.u8 {d5, d6, d7}, [r0], r1 + + mov r2, #3 ;loop counter + vld1.u8 {d8, d9, d10}, [r0], r1 + + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {d11, d12, d13}, [r0], r1 + + vdup.8 d1, d31[4] + +;First Pass: output_height lines x output_width columns (17x16) +vp8e_filt_blk2d_fp16x16_loop_neon + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vqrshrn.u16 d21, q14, #7 + vld1.u8 {d5, d6, d7}, [r0], r1 + + vst1.u8 {d14, d15, d16, d17}, [lr]! ;store result + vld1.u8 {d8, d9, d10}, [r0], r1 + vst1.u8 {d18, d19, d20, d21}, [lr]! + vld1.u8 {d11, d12, d13}, [r0], r1 + + bne vp8e_filt_blk2d_fp16x16_loop_neon + +;First-pass filtering for rest 5 lines + vld1.u8 {d14, d15, d16}, [r0], r1 + + vmull.u8 q9, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q10, d3, d0 + vmull.u8 q11, d5, d0 + vmull.u8 q12, d6, d0 + vmull.u8 q13, d8, d0 + vmull.u8 q14, d9, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + + vmlal.u8 q9, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q11, d5, d1 + vmlal.u8 q13, d8, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + + vmlal.u8 q10, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q12, d6, d1 + vmlal.u8 q14, d9, d1 + + vmull.u8 q1, d11, d0 + vmull.u8 q2, d12, d0 + vmull.u8 q3, d14, d0 + vmull.u8 q4, d15, d0 + + vext.8 d11, d11, d12, #1 ;construct src_ptr[1] + vext.8 d14, d14, d15, #1 + + vmlal.u8 q1, d11, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q3, d14, d1 + + vext.8 d12, d12, d13, #1 + vext.8 d15, d15, d16, #1 + + vmlal.u8 q2, d12, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q4, d15, d1 + + vqrshrn.u16 d10, q9, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d11, q10, #7 + vqrshrn.u16 d12, q11, #7 + vqrshrn.u16 d13, q12, #7 + vqrshrn.u16 d14, q13, #7 + vqrshrn.u16 d15, q14, #7 + vqrshrn.u16 d16, q1, #7 + vqrshrn.u16 d17, q2, #7 + vqrshrn.u16 d18, q3, #7 + vqrshrn.u16 d19, q4, #7 + + vst1.u8 {d10, d11, d12, d13}, [lr]! ;store result + vst1.u8 {d14, d15, d16, d17}, [lr]! + vst1.u8 {d18, d19}, [lr]! + +;Second pass: 16x16 +;secondpass_filter + add r3, r12, r3, lsl #3 + sub lr, lr, #272 + + vld1.u32 {d31}, [r3] ;load second_pass filter + + sub sp, sp, #256 + mov r3, sp + + vld1.u8 {d22, d23}, [lr]! ;load src data + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + mov r12, #4 ;loop counter + +vp8e_filt_blk2d_sp16x16_loop_neon + vld1.u8 {d24, d25}, [lr]! + vmull.u8 q1, d22, d0 ;(src_ptr[0] * Filter[0]) + vld1.u8 {d26, d27}, [lr]! + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [lr]! + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [lr]! + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * Filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + subs r12, r12, #1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r3]! ;store result + vst1.u8 {d4, d5}, [r3]! + vst1.u8 {d6, d7}, [r3]! + vmov q11, q15 + vst1.u8 {d8, d9}, [r3]! + + bne vp8e_filt_blk2d_sp16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;-------------------- +firstpass_bfilter16x16_only + mov r2, #4 ;loop counter + sub sp, sp, #528 ;reserve space on stack for temporary storage + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vdup.8 d1, d31[4] + mov r3, sp + +;First Pass: output_height lines x output_width columns (16x16) +vp8e_filt_blk2d_fpo16x16_loop_neon + vld1.u8 {d2, d3, d4}, [r0], r1 ;load src data + vld1.u8 {d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10}, [r0], r1 + vld1.u8 {d11, d12, d13}, [r0], r1 + + pld [r0] + pld [r0, r1] + pld [r0, r1, lsl #1] + + vmull.u8 q7, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q8, d3, d0 + vmull.u8 q9, d5, d0 + vmull.u8 q10, d6, d0 + vmull.u8 q11, d8, d0 + vmull.u8 q12, d9, d0 + vmull.u8 q13, d11, d0 + vmull.u8 q14, d12, d0 + + vext.8 d2, d2, d3, #1 ;construct src_ptr[1] + vext.8 d5, d5, d6, #1 + vext.8 d8, d8, d9, #1 + vext.8 d11, d11, d12, #1 + + vmlal.u8 q7, d2, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q9, d5, d1 + vmlal.u8 q11, d8, d1 + vmlal.u8 q13, d11, d1 + + vext.8 d3, d3, d4, #1 + vext.8 d6, d6, d7, #1 + vext.8 d9, d9, d10, #1 + vext.8 d12, d12, d13, #1 + + vmlal.u8 q8, d3, d1 ;(src_ptr[0] * Filter[1]) + vmlal.u8 q10, d6, d1 + vmlal.u8 q12, d9, d1 + vmlal.u8 q14, d12, d1 + + subs r2, r2, #1 + + vqrshrn.u16 d14, q7, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d15, q8, #7 + vqrshrn.u16 d16, q9, #7 + vqrshrn.u16 d17, q10, #7 + vqrshrn.u16 d18, q11, #7 + vqrshrn.u16 d19, q12, #7 + vqrshrn.u16 d20, q13, #7 + vst1.u8 {d14, d15}, [r3]! ;store result + vqrshrn.u16 d21, q14, #7 + + vst1.u8 {d16, d17}, [r3]! + vst1.u8 {d18, d19}, [r3]! + vst1.u8 {d20, d21}, [r3]! + + bne vp8e_filt_blk2d_fpo16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;--------------------- +secondpass_bfilter16x16_only +;Second pass: 16x16 +;secondpass_filter + sub sp, sp, #528 ;reserve space on stack for temporary storage + add r3, r12, r3, lsl #3 + mov r12, #4 ;loop counter + vld1.u32 {d31}, [r3] ;load second_pass filter + vld1.u8 {d22, d23}, [r0], r1 ;load src data + mov r3, sp + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + +vp8e_filt_blk2d_spo16x16_loop_neon + vld1.u8 {d24, d25}, [r0], r1 + vmull.u8 q1, d22, d0 ;(src_ptr[0] * Filter[0]) + vld1.u8 {d26, d27}, [r0], r1 + vmull.u8 q2, d23, d0 + vld1.u8 {d28, d29}, [r0], r1 + vmull.u8 q3, d24, d0 + vld1.u8 {d30, d31}, [r0], r1 + + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d24, d1 ;(src_ptr[pixel_step] * Filter[1]) + vmlal.u8 q2, d25, d1 + vmlal.u8 q3, d26, d1 + vmlal.u8 q4, d27, d1 + vmlal.u8 q5, d28, d1 + vmlal.u8 q6, d29, d1 + vmlal.u8 q7, d30, d1 + vmlal.u8 q8, d31, d1 + + vqrshrn.u16 d2, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d3, q2, #7 + vqrshrn.u16 d4, q3, #7 + vqrshrn.u16 d5, q4, #7 + vqrshrn.u16 d6, q5, #7 + vqrshrn.u16 d7, q6, #7 + vqrshrn.u16 d8, q7, #7 + vqrshrn.u16 d9, q8, #7 + + vst1.u8 {d2, d3}, [r3]! ;store result + subs r12, r12, #1 + vst1.u8 {d4, d5}, [r3]! + vmov q11, q15 + vst1.u8 {d6, d7}, [r3]! + vst1.u8 {d8, d9}, [r3]! + + bne vp8e_filt_blk2d_spo16x16_loop_neon + + b sub_pixel_variance16x16_neon + +;---------------------------- +;variance16x16 +sub_pixel_variance16x16_neon + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + sub r3, r3, #256 + mov r12, #8 + +sub_pixel_variance16x16_neon_loop + vld1.8 {q0}, [r3]! ;Load up source and reference + vld1.8 {q2}, [r4], r5 + vld1.8 {q1}, [r3]! + vld1.8 {q3}, [r4], r5 + + vsubl.u8 q11, d0, d4 ;diff + vsubl.u8 q12, d1, d5 + vsubl.u8 q13, d2, d6 + vsubl.u8 q14, d3, d7 + + vpadal.s16 q8, q11 ;sum + vmlal.s16 q9, d22, d22 ;sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + bne sub_pixel_variance16x16_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [r6] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + add sp, sp, #528 + vmov.32 r0, d0[0] ;return + + pop {r4-r6,pc} + + ENDP + +;----------------- + AREA vp8e_bilinear_taps_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_BilinearTaps_coeff_ + DCD bilinear_taps_coeff +bilinear_taps_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/encoder/arm/neon/vp8_subpixelvariance16x16s_neon.asm b/vp8/encoder/arm/neon/vp8_subpixelvariance16x16s_neon.asm new file mode 100644 index 0000000..3d02d7c --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_subpixelvariance16x16s_neon.asm
@@ -0,0 +1,571 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sub_pixel_variance16x16s_4_0_neon| + EXPORT |vp8_sub_pixel_variance16x16s_0_4_neon| + EXPORT |vp8_sub_pixel_variance16x16s_4_4_neon| + EXPORT |vp8_sub_pixel_variance16x16s_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 + +;================================================ +;unsigned int vp8_sub_pixel_variance16x16s_4_0_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_sub_pixel_variance16x16s_4_0_neon| PROC + push {lr} + + mov r12, #4 ;loop counter + ldr lr, [sp, #4] ;load *sse from stack + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + +;First Pass: output_height lines x output_width columns (16x16) +vp8_filt_fpo16x16s_4_0_loop_neon + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + vld1.8 {q11}, [r2], r3 + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.8 {q12}, [r2], r3 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.8 {q13}, [r2], r3 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + vext.8 q3, q2, q3, #1 + vext.8 q5, q4, q5, #1 + vext.8 q7, q6, q7, #1 + + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vld1.8 {q14}, [r2], r3 + vrhadd.u8 q1, q2, q3 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + + vsubl.u8 q4, d0, d22 ;diff + vsubl.u8 q5, d1, d23 + vsubl.u8 q6, d2, d24 + vsubl.u8 q7, d3, d25 + vsubl.u8 q0, d4, d26 + vsubl.u8 q1, d5, d27 + vsubl.u8 q2, d6, d28 + vsubl.u8 q3, d7, d29 + + vpadal.s16 q8, q4 ;sum + vmlal.s16 q9, d8, d8 ;sse + vmlal.s16 q10, d9, d9 + + subs r12, r12, #1 + + vpadal.s16 q8, q5 + vmlal.s16 q9, d10, d10 + vmlal.s16 q10, d11, d11 + vpadal.s16 q8, q6 + vmlal.s16 q9, d12, d12 + vmlal.s16 q10, d13, d13 + vpadal.s16 q8, q7 + vmlal.s16 q9, d14, d14 + vmlal.s16 q10, d15, d15 + + vpadal.s16 q8, q0 ;sum + vmlal.s16 q9, d0, d0 ;sse + vmlal.s16 q10, d1, d1 + vpadal.s16 q8, q1 + vmlal.s16 q9, d2, d2 + vmlal.s16 q10, d3, d3 + vpadal.s16 q8, q2 + vmlal.s16 q9, d4, d4 + vmlal.s16 q10, d5, d5 + vpadal.s16 q8, q3 + vmlal.s16 q9, d6, d6 + vmlal.s16 q10, d7, d7 + + bne vp8_filt_fpo16x16s_4_0_loop_neon + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;================================================ +;unsigned int vp8_sub_pixel_variance16x16s_0_4_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_sub_pixel_variance16x16s_0_4_neon| PROC + push {lr} + + mov r12, #4 ;loop counter + + vld1.u8 {q0}, [r0], r1 ;load src data + ldr lr, [sp, #4] ;load *sse from stack + + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + +vp8_filt_spo16x16s_0_4_loop_neon + vld1.u8 {q2}, [r0], r1 + vld1.8 {q1}, [r2], r3 + vld1.u8 {q4}, [r0], r1 + vld1.8 {q3}, [r2], r3 + vld1.u8 {q6}, [r0], r1 + vld1.8 {q5}, [r2], r3 + vld1.u8 {q15}, [r0], r1 + + vrhadd.u8 q0, q0, q2 + vld1.8 {q7}, [r2], r3 + vrhadd.u8 q2, q2, q4 + vrhadd.u8 q4, q4, q6 + vrhadd.u8 q6, q6, q15 + + vsubl.u8 q11, d0, d2 ;diff + vsubl.u8 q12, d1, d3 + vsubl.u8 q13, d4, d6 + vsubl.u8 q14, d5, d7 + vsubl.u8 q0, d8, d10 + vsubl.u8 q1, d9, d11 + vsubl.u8 q2, d12, d14 + vsubl.u8 q3, d13, d15 + + vpadal.s16 q8, q11 ;sum + vmlal.s16 q9, d22, d22 ;sse + vmlal.s16 q10, d23, d23 + + subs r12, r12, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + vpadal.s16 q8, q0 ;sum + vmlal.s16 q9, d0, d0 ;sse + vmlal.s16 q10, d1, d1 + vpadal.s16 q8, q1 + vmlal.s16 q9, d2, d2 + vmlal.s16 q10, d3, d3 + vpadal.s16 q8, q2 + vmlal.s16 q9, d4, d4 + vmlal.s16 q10, d5, d5 + + vmov q0, q15 + + vpadal.s16 q8, q3 + vmlal.s16 q9, d6, d6 + vmlal.s16 q10, d7, d7 + + bne vp8_filt_spo16x16s_0_4_loop_neon + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;================================================ +;unsigned int vp8_sub_pixel_variance16x16s_4_4_neon +;( +; unsigned char *src_ptr, r0 +; int src_pixels_per_line, r1 +; unsigned char *dst_ptr, r2 +; int dst_pixels_per_line, r3 +; unsigned int *sse +;); +;================================================ +|vp8_sub_pixel_variance16x16s_4_4_neon| PROC + push {lr} + + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + + ldr lr, [sp, #4] ;load *sse from stack + vmov.i8 q13, #0 ;q8 - sum + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + + vmov.i8 q14, #0 ;q9, q10 - sse + vmov.i8 q15, #0 + + mov r12, #4 ;loop counter + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + +;First Pass: output_height lines x output_width columns (17x16) +vp8_filt16x16s_4_4_loop_neon + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + vld1.u8 {d16, d17, d18, d19}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q3, q2, q3, #1 ;construct src_ptr[1] + vext.8 q5, q4, q5, #1 + vext.8 q7, q6, q7, #1 + vext.8 q9, q8, q9, #1 + + vrhadd.u8 q1, q2, q3 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + vrhadd.u8 q4, q8, q9 + + vld1.8 {q5}, [r2], r3 + vrhadd.u8 q0, q0, q1 + vld1.8 {q6}, [r2], r3 + vrhadd.u8 q1, q1, q2 + vld1.8 {q7}, [r2], r3 + vrhadd.u8 q2, q2, q3 + vld1.8 {q8}, [r2], r3 + vrhadd.u8 q3, q3, q4 + + vsubl.u8 q9, d0, d10 ;diff + vsubl.u8 q10, d1, d11 + vsubl.u8 q11, d2, d12 + vsubl.u8 q12, d3, d13 + + vsubl.u8 q0, d4, d14 ;diff + vsubl.u8 q1, d5, d15 + vsubl.u8 q5, d6, d16 + vsubl.u8 q6, d7, d17 + + vpadal.s16 q13, q9 ;sum + vmlal.s16 q14, d18, d18 ;sse + vmlal.s16 q15, d19, d19 + + vpadal.s16 q13, q10 ;sum + vmlal.s16 q14, d20, d20 ;sse + vmlal.s16 q15, d21, d21 + + vpadal.s16 q13, q11 ;sum + vmlal.s16 q14, d22, d22 ;sse + vmlal.s16 q15, d23, d23 + + vpadal.s16 q13, q12 ;sum + vmlal.s16 q14, d24, d24 ;sse + vmlal.s16 q15, d25, d25 + + subs r12, r12, #1 + + vpadal.s16 q13, q0 ;sum + vmlal.s16 q14, d0, d0 ;sse + vmlal.s16 q15, d1, d1 + + vpadal.s16 q13, q1 ;sum + vmlal.s16 q14, d2, d2 ;sse + vmlal.s16 q15, d3, d3 + + vpadal.s16 q13, q5 ;sum + vmlal.s16 q14, d10, d10 ;sse + vmlal.s16 q15, d11, d11 + + vmov q0, q4 + + vpadal.s16 q13, q6 ;sum + vmlal.s16 q14, d12, d12 ;sse + vmlal.s16 q15, d13, d13 + + bne vp8_filt16x16s_4_4_loop_neon + + vadd.u32 q15, q14, q15 ;accumulate sse + vpaddl.s32 q0, q13 ;accumulate sum + + vpaddl.u32 q1, q15 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {pc} + ENDP + +;============================== +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack unsigned char *dst_ptr, +; stack int dst_pixels_per_line, +; stack unsigned int *sse +;note: in vp8_find_best_half_pixel_step()(called when 8<Speed<15), and first call of vp8_find_best_sub_pixel_step() +;(called when speed<=8). xoffset/yoffset can only be 4 or 0, which means either by pass the filter, +;or filter coeff is {64, 64}. This simplified program only works in this situation. +;note: It happens that both xoffset and yoffset are zero. This can be handled in c code later. + +|vp8_sub_pixel_variance16x16s_neon| PROC + push {r4, lr} + + ldr r4, [sp, #8] ;load *dst_ptr from stack + ldr r12, [sp, #12] ;load dst_pixels_per_line from stack + ldr lr, [sp, #16] ;load *sse from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq secondpass_bfilter16x16s_only + + cmp r3, #0 ;skip second_pass filter if yoffset=0 + beq firstpass_bfilter16x16s_only + + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + sub sp, sp, #256 ;reserve space on stack for temporary storage + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + mov r3, sp + mov r2, #4 ;loop counter + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + +;First Pass: output_height lines x output_width columns (17x16) +vp8e_filt_blk2d_fp16x16s_loop_neon + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + vld1.u8 {d16, d17, d18, d19}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q3, q2, q3, #1 ;construct src_ptr[1] + vext.8 q5, q4, q5, #1 + vext.8 q7, q6, q7, #1 + vext.8 q9, q8, q9, #1 + + vrhadd.u8 q1, q2, q3 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + vrhadd.u8 q4, q8, q9 + + vrhadd.u8 q0, q0, q1 + vrhadd.u8 q1, q1, q2 + vrhadd.u8 q2, q2, q3 + vrhadd.u8 q3, q3, q4 + + subs r2, r2, #1 + vst1.u8 {d0, d1 ,d2, d3}, [r3]! ;store result + vmov q0, q4 + vst1.u8 {d4, d5, d6, d7}, [r3]! + + bne vp8e_filt_blk2d_fp16x16s_loop_neon + + b sub_pixel_variance16x16s_neon + +;-------------------- +firstpass_bfilter16x16s_only + mov r2, #2 ;loop counter + sub sp, sp, #256 ;reserve space on stack for temporary storage + mov r3, sp + +;First Pass: output_height lines x output_width columns (16x16) +vp8e_filt_blk2d_fpo16x16s_loop_neon + vld1.u8 {d0, d1, d2, d3}, [r0], r1 ;load src data + vld1.u8 {d4, d5, d6, d7}, [r0], r1 + vld1.u8 {d8, d9, d10, d11}, [r0], r1 + vld1.u8 {d12, d13, d14, d15}, [r0], r1 + + ;pld [r0] + ;pld [r0, r1] + ;pld [r0, r1, lsl #1] + + vext.8 q1, q0, q1, #1 ;construct src_ptr[1] + vld1.u8 {d16, d17, d18, d19}, [r0], r1 + vext.8 q3, q2, q3, #1 + vld1.u8 {d20, d21, d22, d23}, [r0], r1 + vext.8 q5, q4, q5, #1 + vld1.u8 {d24, d25, d26, d27}, [r0], r1 + vext.8 q7, q6, q7, #1 + vld1.u8 {d28, d29, d30, d31}, [r0], r1 + vext.8 q9, q8, q9, #1 + vext.8 q11, q10, q11, #1 + vext.8 q13, q12, q13, #1 + vext.8 q15, q14, q15, #1 + + vrhadd.u8 q0, q0, q1 ;(src_ptr[0]+src_ptr[1])/round/shift right 1 + vrhadd.u8 q1, q2, q3 + vrhadd.u8 q2, q4, q5 + vrhadd.u8 q3, q6, q7 + vrhadd.u8 q4, q8, q9 + vrhadd.u8 q5, q10, q11 + vrhadd.u8 q6, q12, q13 + vrhadd.u8 q7, q14, q15 + + subs r2, r2, #1 + + vst1.u8 {d0, d1, d2, d3}, [r3]! ;store result + vst1.u8 {d4, d5, d6, d7}, [r3]! + vst1.u8 {d8, d9, d10, d11}, [r3]! + vst1.u8 {d12, d13, d14, d15}, [r3]! + + bne vp8e_filt_blk2d_fpo16x16s_loop_neon + + b sub_pixel_variance16x16s_neon + +;--------------------- +secondpass_bfilter16x16s_only + sub sp, sp, #256 ;reserve space on stack for temporary storage + + mov r2, #2 ;loop counter + vld1.u8 {d0, d1}, [r0], r1 ;load src data + mov r3, sp + +vp8e_filt_blk2d_spo16x16s_loop_neon + vld1.u8 {d2, d3}, [r0], r1 + vld1.u8 {d4, d5}, [r0], r1 + vld1.u8 {d6, d7}, [r0], r1 + vld1.u8 {d8, d9}, [r0], r1 + + vrhadd.u8 q0, q0, q1 + vld1.u8 {d10, d11}, [r0], r1 + vrhadd.u8 q1, q1, q2 + vld1.u8 {d12, d13}, [r0], r1 + vrhadd.u8 q2, q2, q3 + vld1.u8 {d14, d15}, [r0], r1 + vrhadd.u8 q3, q3, q4 + vld1.u8 {d16, d17}, [r0], r1 + vrhadd.u8 q4, q4, q5 + vrhadd.u8 q5, q5, q6 + vrhadd.u8 q6, q6, q7 + vrhadd.u8 q7, q7, q8 + + subs r2, r2, #1 + + vst1.u8 {d0, d1, d2, d3}, [r3]! ;store result + vmov q0, q8 + vst1.u8 {d4, d5, d6, d7}, [r3]! + vst1.u8 {d8, d9, d10, d11}, [r3]! ;store result + vst1.u8 {d12, d13, d14, d15}, [r3]! + + bne vp8e_filt_blk2d_spo16x16s_loop_neon + + b sub_pixel_variance16x16s_neon + +;---------------------------- +;variance16x16 +sub_pixel_variance16x16s_neon + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + sub r3, r3, #256 + mov r2, #4 + +sub_pixel_variance16x16s_neon_loop + vld1.8 {q0}, [r3]! ;Load up source and reference + vld1.8 {q1}, [r4], r12 + vld1.8 {q2}, [r3]! + vld1.8 {q3}, [r4], r12 + vld1.8 {q4}, [r3]! + vld1.8 {q5}, [r4], r12 + vld1.8 {q6}, [r3]! + vld1.8 {q7}, [r4], r12 + + vsubl.u8 q11, d0, d2 ;diff + vsubl.u8 q12, d1, d3 + vsubl.u8 q13, d4, d6 + vsubl.u8 q14, d5, d7 + vsubl.u8 q0, d8, d10 + vsubl.u8 q1, d9, d11 + vsubl.u8 q2, d12, d14 + vsubl.u8 q3, d13, d15 + + vpadal.s16 q8, q11 ;sum + vmlal.s16 q9, d22, d22 ;sse + vmlal.s16 q10, d23, d23 + + subs r2, r2, #1 + + vpadal.s16 q8, q12 + vmlal.s16 q9, d24, d24 + vmlal.s16 q10, d25, d25 + vpadal.s16 q8, q13 + vmlal.s16 q9, d26, d26 + vmlal.s16 q10, d27, d27 + vpadal.s16 q8, q14 + vmlal.s16 q9, d28, d28 + vmlal.s16 q10, d29, d29 + + vpadal.s16 q8, q0 ;sum + vmlal.s16 q9, d0, d0 ;sse + vmlal.s16 q10, d1, d1 + vpadal.s16 q8, q1 + vmlal.s16 q9, d2, d2 + vmlal.s16 q10, d3, d3 + vpadal.s16 q8, q2 + vmlal.s16 q9, d4, d4 + vmlal.s16 q10, d5, d5 + vpadal.s16 q8, q3 + vmlal.s16 q9, d6, d6 + vmlal.s16 q10, d7, d7 + + bne sub_pixel_variance16x16s_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.s32 d10, d10, #8 + vsub.s32 d0, d1, d10 + + add sp, sp, #256 + vmov.32 r0, d0[0] ;return + + pop {r4, pc} + ENDP + + END
diff --git a/vp8/encoder/arm/neon/vp8_subpixelvariance8x8_neon.asm b/vp8/encoder/arm/neon/vp8_subpixelvariance8x8_neon.asm new file mode 100644 index 0000000..bd56761 --- /dev/null +++ b/vp8/encoder/arm/neon/vp8_subpixelvariance8x8_neon.asm
@@ -0,0 +1,226 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + EXPORT |vp8_sub_pixel_variance8x8_neon| + ARM + REQUIRE8 + PRESERVE8 + + AREA ||.text||, CODE, READONLY, ALIGN=2 +; r0 unsigned char *src_ptr, +; r1 int src_pixels_per_line, +; r2 int xoffset, +; r3 int yoffset, +; stack(r4) unsigned char *dst_ptr, +; stack(r5) int dst_pixels_per_line, +; stack(r6) unsigned int *sse +;note: most of the code is copied from bilinear_predict8x8_neon and vp8_variance8x8_neon. + +|vp8_sub_pixel_variance8x8_neon| PROC + push {r4-r5, lr} + + ldr r12, _BilinearTaps_coeff_ + ldr r4, [sp, #12] ;load *dst_ptr from stack + ldr r5, [sp, #16] ;load dst_pixels_per_line from stack + ldr lr, [sp, #20] ;load *sse from stack + + cmp r2, #0 ;skip first_pass filter if xoffset=0 + beq skip_firstpass_filter + +;First pass: output_height lines x output_width columns (9x8) + add r2, r12, r2, lsl #3 ;calculate filter location + + vld1.u8 {q1}, [r0], r1 ;load src data + vld1.u32 {d31}, [r2] ;load first_pass filter + vld1.u8 {q2}, [r0], r1 + vdup.8 d0, d31[0] ;first_pass filter (d0 d1) + vld1.u8 {q3}, [r0], r1 + vdup.8 d1, d31[4] + vld1.u8 {q4}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * Filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + + vld1.u8 {q1}, [r0], r1 ;load src data + vqrshrn.u16 d22, q6, #7 ;shift/round/saturate to u8 + vld1.u8 {q2}, [r0], r1 + vqrshrn.u16 d23, q7, #7 + vld1.u8 {q3}, [r0], r1 + vqrshrn.u16 d24, q8, #7 + vld1.u8 {q4}, [r0], r1 + vqrshrn.u16 d25, q9, #7 + + ;first_pass filtering on the rest 5-line data + vld1.u8 {q5}, [r0], r1 + + vmull.u8 q6, d2, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q7, d4, d0 + vmull.u8 q8, d6, d0 + vmull.u8 q9, d8, d0 + vmull.u8 q10, d10, d0 + + vext.8 d3, d2, d3, #1 ;construct src_ptr[-1] + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 + + vmlal.u8 q6, d3, d1 ;(src_ptr[1] * Filter[1]) + vmlal.u8 q7, d5, d1 + vmlal.u8 q8, d7, d1 + vmlal.u8 q9, d9, d1 + vmlal.u8 q10, d11, d1 + + vqrshrn.u16 d26, q6, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d27, q7, #7 + vqrshrn.u16 d28, q8, #7 + vqrshrn.u16 d29, q9, #7 + vqrshrn.u16 d30, q10, #7 + +;Second pass: 8x8 +secondpass_filter + cmp r3, #0 ;skip second_pass filter if yoffset=0 + ;skip_secondpass_filter + beq sub_pixel_variance8x8_neon + + add r3, r12, r3, lsl #3 + + vld1.u32 {d31}, [r3] ;load second_pass filter + + vdup.8 d0, d31[0] ;second_pass filter parameters (d0 d1) + vdup.8 d1, d31[4] + + vmull.u8 q1, d22, d0 ;(src_ptr[0] * Filter[0]) + vmull.u8 q2, d23, d0 + vmull.u8 q3, d24, d0 + vmull.u8 q4, d25, d0 + vmull.u8 q5, d26, d0 + vmull.u8 q6, d27, d0 + vmull.u8 q7, d28, d0 + vmull.u8 q8, d29, d0 + + vmlal.u8 q1, d23, d1 ;(src_ptr[pixel_step] * Filter[1]) + vmlal.u8 q2, d24, d1 + vmlal.u8 q3, d25, d1 + vmlal.u8 q4, d26, d1 + vmlal.u8 q5, d27, d1 + vmlal.u8 q6, d28, d1 + vmlal.u8 q7, d29, d1 + vmlal.u8 q8, d30, d1 + + vqrshrn.u16 d22, q1, #7 ;shift/round/saturate to u8 + vqrshrn.u16 d23, q2, #7 + vqrshrn.u16 d24, q3, #7 + vqrshrn.u16 d25, q4, #7 + vqrshrn.u16 d26, q5, #7 + vqrshrn.u16 d27, q6, #7 + vqrshrn.u16 d28, q7, #7 + vqrshrn.u16 d29, q8, #7 + + b sub_pixel_variance8x8_neon + +;-------------------- +skip_firstpass_filter + vld1.u8 {d22}, [r0], r1 ;load src data + vld1.u8 {d23}, [r0], r1 + vld1.u8 {d24}, [r0], r1 + vld1.u8 {d25}, [r0], r1 + vld1.u8 {d26}, [r0], r1 + vld1.u8 {d27}, [r0], r1 + vld1.u8 {d28}, [r0], r1 + vld1.u8 {d29}, [r0], r1 + vld1.u8 {d30}, [r0], r1 + + b secondpass_filter + +;---------------------- +;vp8_variance8x8_neon +sub_pixel_variance8x8_neon + vmov.i8 q8, #0 ;q8 - sum + vmov.i8 q9, #0 ;q9, q10 - sse + vmov.i8 q10, #0 + + mov r12, #2 + +sub_pixel_variance8x8_neon_loop + vld1.8 {d0}, [r4], r5 ;load dst data + subs r12, r12, #1 + vld1.8 {d1}, [r4], r5 + vld1.8 {d2}, [r4], r5 + vsubl.u8 q4, d22, d0 ;calculate diff + vld1.8 {d3}, [r4], r5 + + vsubl.u8 q5, d23, d1 + vsubl.u8 q6, d24, d2 + + vpadal.s16 q8, q4 ;sum + vmlal.s16 q9, d8, d8 ;sse + vmlal.s16 q10, d9, d9 + + vsubl.u8 q7, d25, d3 + + vpadal.s16 q8, q5 + vmlal.s16 q9, d10, d10 + vmlal.s16 q10, d11, d11 + + vmov q11, q13 + + vpadal.s16 q8, q6 + vmlal.s16 q9, d12, d12 + vmlal.s16 q10, d13, d13 + + vmov q12, q14 + + vpadal.s16 q8, q7 + vmlal.s16 q9, d14, d14 + vmlal.s16 q10, d15, d15 + + bne sub_pixel_variance8x8_neon_loop + + vadd.u32 q10, q9, q10 ;accumulate sse + vpaddl.s32 q0, q8 ;accumulate sum + + vpaddl.u32 q1, q10 + vadd.s64 d0, d0, d1 + vadd.u64 d1, d2, d3 + + vmull.s32 q5, d0, d0 + vst1.32 {d1[0]}, [lr] ;store sse + vshr.s32 d10, d10, #6 + vsub.s32 d0, d1, d10 + + vmov.32 r0, d0[0] ;return + pop {r4-r5, pc} + + ENDP + +;----------------- + AREA bilinear_taps_dat, DATA, READWRITE ;read/write by default +;Data section with name data_area is specified. DCD reserves space in memory for 48 data. +;One word each is reserved. Label filter_coeff can be used to access the data. +;Data address: filter_coeff, filter_coeff+4, filter_coeff+8 ... +_BilinearTaps_coeff_ + DCD bilinear_taps_coeff +bilinear_taps_coeff + DCD 128, 0, 112, 16, 96, 32, 80, 48, 64, 64, 48, 80, 32, 96, 16, 112 + + END
diff --git a/vp8/encoder/arm/picklpf_arm.c b/vp8/encoder/arm/picklpf_arm.c new file mode 100644 index 0000000..0586e55 --- /dev/null +++ b/vp8/encoder/arm/picklpf_arm.c
@@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxc_int.h" +#include "onyx_int.h" +#include "quantize.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/yv12extend.h" +#include "vpx_scale/vpxscale.h" +#include "alloccommon.h" + +extern void vp8_memcpy_neon(unsigned char *dst_ptr, unsigned char *src_ptr, int sz); + + +void +vpxyv12_copy_partial_frame_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction) +{ + unsigned char *src_y, *dst_y; + int yheight; + int ystride; + int border; + int yoffset; + int linestocopy; + + border = src_ybc->border; + yheight = src_ybc->y_height; + ystride = src_ybc->y_stride; + + linestocopy = (yheight >> (Fraction + 4)); + + if (linestocopy < 1) + linestocopy = 1; + + linestocopy <<= 4; + + yoffset = ystride * ((yheight >> 5) * 16 - 8); + src_y = src_ybc->y_buffer + yoffset; + dst_y = dst_ybc->y_buffer + yoffset; + + //vpx_memcpy (dst_y, src_y, ystride * (linestocopy +16)); + vp8_memcpy_neon((unsigned char *)dst_y, (unsigned char *)src_y, (int)(ystride *(linestocopy + 16))); +}
diff --git a/vp8/encoder/arm/quantize_arm.c b/vp8/encoder/arm/quantize_arm.c new file mode 100644 index 0000000..46906d3 --- /dev/null +++ b/vp8/encoder/arm/quantize_arm.c
@@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> +#include "vpx_mem/vpx_mem.h" + +#include "quantize.h" +#include "entropy.h" +#include "predictdc.h" + +DECLARE_ALIGNED(16, const short, vp8_rvsplus1_default_zig_zag1d[16]) = +{ + 1, 2, 6, 7, + 3, 5, 8, 13, + 4, 9, 12, 14, + 10, 11, 15, 16, +}; + + +extern int vp8_fast_quantize_b_neon_func(short *coeff_ptr, short *zbin_ptr, short *qcoeff_ptr, short *dqcoeff_ptr, short *dequant_ptr, const short *scan_mask, short *round_ptr, short *quant_ptr); + +void vp8_fast_quantize_b_neon(BLOCK *b, BLOCKD *d) +{ + d->eob = vp8_fast_quantize_b_neon_func(b->coeff, &b->zbin[0][0], d->qcoeff, d->dqcoeff, d->dequant[0], vp8_rvsplus1_default_zig_zag1d, &b->round[0][0], &b->quant[0][0]); +} + +/* +//neon code is written according to the following rewritten c code +void vp8_fast_quantize_b_neon(BLOCK *b,BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, x1, y, z, sz; + short *coeff_ptr = &b->Coeff[0]; + short *zbin_ptr = &b->Zbin[0][0]; + short *round_ptr = &b->Round[0][0]; + short *quant_ptr = &b->Quant[0][0]; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr= d->dqcoeff; + short *dequant_ptr= &d->Dequant[0][0]; + + eob = 0; + + for(i=0;i<16;i++) + { + z = coeff_ptr[i]; + zbin = zbin_ptr[i] ; + x = abs(z); // x = abs(z) + + if(x>=zbin) + { + sz = (z>>31); // sign of z + y = ((x+round_ptr[i])*quant_ptr[i])>>16; // quantize (x) + x1 = (y^sz) - sz; // get the sign back + + qcoeff_ptr[i] = x1; // write to destination + dqcoeff_ptr[i] = x1 * dequant_ptr[i]; // dequantized value + + if(y) + { + if(eob<vp8_rvsplus1_default_zig_zag1d[i]) + eob=(int)vp8_rvsplus1_default_zig_zag1d[i]; // last nonzero coeffs + } + }else + { + qcoeff_ptr[i] = 0; // write to destination + dqcoeff_ptr[i] = 0; // dequantized value + } + } + d->eob = eob; +} +*/
diff --git a/vp8/encoder/arm/quantize_arm.h b/vp8/encoder/arm/quantize_arm.h new file mode 100644 index 0000000..e93f0fe --- /dev/null +++ b/vp8/encoder/arm/quantize_arm.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef QUANTIZE_ARM_H +#define QUANTIZE_ARM_H + +#if HAVE_ARMV7 +extern prototype_quantize_block(vp8_fast_quantize_b_neon); + +#undef vp8_quantize_fastquantb +#define vp8_quantize_fastquantb vp8_fast_quantize_b_neon + +#endif + +#endif
diff --git a/vp8/encoder/arm/variance_arm.h b/vp8/encoder/arm/variance_arm.h new file mode 100644 index 0000000..d9fc9b3 --- /dev/null +++ b/vp8/encoder/arm/variance_arm.h
@@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef VARIANCE_ARM_H +#define VARIANCE_ARM_H + +#if HAVE_ARMV7 +extern prototype_sad(vp8_sad4x4_neon); +extern prototype_sad(vp8_sad8x8_neon); +extern prototype_sad(vp8_sad8x16_neon); +extern prototype_sad(vp8_sad16x8_neon); +extern prototype_sad(vp8_sad16x16_neon); + +//extern prototype_variance(vp8_variance4x4_c); +extern prototype_variance(vp8_variance8x8_neon); +extern prototype_variance(vp8_variance8x16_neon); +extern prototype_variance(vp8_variance16x8_neon); +extern prototype_variance(vp8_variance16x16_neon); + +//extern prototype_subpixvariance(vp8_sub_pixel_variance4x4_c); +extern prototype_subpixvariance(vp8_sub_pixel_variance8x8_neon); +//extern prototype_subpixvariance(vp8_sub_pixel_variance8x16_c); +//extern prototype_subpixvariance(vp8_sub_pixel_variance16x8_c); +extern prototype_subpixvariance(vp8_sub_pixel_variance16x16_neon); + +//extern prototype_getmbss(vp8_get_mb_ss_c); +extern prototype_variance(vp8_mse16x16_neon); +extern prototype_sad(vp8_get16x16pred_error_neon); +//extern prototype_variance2(vp8_get8x8var_c); +//extern prototype_variance2(vp8_get16x16var_c); +extern prototype_sad(vp8_get4x4sse_cs_neon); + +#undef vp8_variance_sad4x4 +#define vp8_variance_sad4x4 vp8_sad4x4_neon + +#undef vp8_variance_sad8x8 +#define vp8_variance_sad8x8 vp8_sad8x8_neon + +#undef vp8_variance_sad8x16 +#define vp8_variance_sad8x16 vp8_sad8x16_neon + +#undef vp8_variance_sad16x8 +#define vp8_variance_sad16x8 vp8_sad16x8_neon + +#undef vp8_variance_sad16x16 +#define vp8_variance_sad16x16 vp8_sad16x16_neon + +//#undef vp8_variance_var4x4 +//#define vp8_variance_var4x4 vp8_variance4x4_c + +#undef vp8_variance_var8x8 +#define vp8_variance_var8x8 vp8_variance8x8_neon + +#undef vp8_variance_var8x16 +#define vp8_variance_var8x16 vp8_variance8x16_neon + +#undef vp8_variance_var16x8 +#define vp8_variance_var16x8 vp8_variance16x8_neon + +#undef vp8_variance_var16x16 +#define vp8_variance_var16x16 vp8_variance16x16_neon + +//#undef vp8_variance_subpixvar4x4 +//#define vp8_variance_subpixvar4x4 vp8_sub_pixel_variance4x4_c + +#undef vp8_variance_subpixvar8x8 +#define vp8_variance_subpixvar8x8 vp8_sub_pixel_variance8x8_neon + +//#undef vp8_variance_subpixvar8x16 +//#define vp8_variance_subpixvar8x16 vp8_sub_pixel_variance8x16_c + +//#undef vp8_variance_subpixvar16x8 +//#define vp8_variance_subpixvar16x8 vp8_sub_pixel_variance16x8_c + +#undef vp8_variance_subpixvar16x16 +#define vp8_variance_subpixvar16x16 vp8_sub_pixel_variance16x16_neon + +//#undef vp8_variance_getmbss +//#define vp8_variance_getmbss vp8_get_mb_ss_c + +#undef vp8_variance_mse16x16 +#define vp8_variance_mse16x16 vp8_mse16x16_neon + +#undef vp8_variance_get16x16prederror +#define vp8_variance_get16x16prederror vp8_get16x16pred_error_neon + +//#undef vp8_variance_get8x8var +//#define vp8_variance_get8x8var vp8_get8x8var_c + +//#undef vp8_variance_get16x16var +//#define vp8_variance_get16x16var vp8_get16x16var_c + +#undef vp8_variance_get4x4sse_cs +#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_neon + +#endif + +#endif
diff --git a/vp8/encoder/arm/vpx_vp8_enc_asm_offsets.c b/vp8/encoder/arm/vpx_vp8_enc_asm_offsets.c new file mode 100644 index 0000000..8cdf079 --- /dev/null +++ b/vp8/encoder/arm/vpx_vp8_enc_asm_offsets.c
@@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include <stddef.h> + +#include "../treewriter.h" +#include "../tokenize.h" +#include "../onyx_int.h" + +#define ct_assert(name,cond) \ + static void assert_##name(void) UNUSED;\ + static void assert_##name(void) {switch(0){case 0:case !!(cond):;}} + +#define DEFINE(sym, val) int sym = val; + +/* +#define BLANK() asm volatile("\n->" : : ) +*/ + +/* + * int main(void) + * { + */ + +DEFINE(vp8_writer_lowvalue, offsetof(vp8_writer, lowvalue)); +DEFINE(vp8_writer_range, offsetof(vp8_writer, range)); +DEFINE(vp8_writer_value, offsetof(vp8_writer, value)); +DEFINE(vp8_writer_count, offsetof(vp8_writer, count)); +DEFINE(vp8_writer_pos, offsetof(vp8_writer, pos)); +DEFINE(vp8_writer_buffer, offsetof(vp8_writer, buffer)); + +DEFINE(tokenextra_token, offsetof(TOKENEXTRA, Token)); +DEFINE(tokenextra_extra, offsetof(TOKENEXTRA, Extra)); +DEFINE(tokenextra_context_tree, offsetof(TOKENEXTRA, context_tree)); +DEFINE(tokenextra_skip_eob_node, offsetof(TOKENEXTRA, skip_eob_node)); +DEFINE(TOKENEXTRA_SZ, sizeof(TOKENEXTRA)); + +DEFINE(vp8_extra_bit_struct_sz, sizeof(vp8_extra_bit_struct)); + +DEFINE(vp8_token_value, offsetof(vp8_token, value)); +DEFINE(vp8_token_len, offsetof(vp8_token, Len)); + +DEFINE(vp8_extra_bit_struct_tree, offsetof(vp8_extra_bit_struct, tree)); +DEFINE(vp8_extra_bit_struct_prob, offsetof(vp8_extra_bit_struct, prob)); +DEFINE(vp8_extra_bit_struct_prob_bc, offsetof(vp8_extra_bit_struct, prob_bc)); +DEFINE(vp8_extra_bit_struct_len, offsetof(vp8_extra_bit_struct, Len)); +DEFINE(vp8_extra_bit_struct_base_val, offsetof(vp8_extra_bit_struct, base_val)); + +DEFINE(vp8_comp_tplist, offsetof(VP8_COMP, tplist)); +DEFINE(vp8_comp_common, offsetof(VP8_COMP, common)); +DEFINE(vp8_comp_bc2, offsetof(VP8_COMP, bc2)); + +DEFINE(tokenlist_start, offsetof(TOKENLIST, start)); +DEFINE(tokenlist_stop, offsetof(TOKENLIST, stop)); +DEFINE(TOKENLIST_SZ, sizeof(TOKENLIST)); + +DEFINE(vp8_common_mb_rows, offsetof(VP8_COMMON, mb_rows)); + +// These two sizes are used in vp7cx_pack_tokens. They are hard coded +// so if the size changes this will have to be adjusted. +ct_assert(TOKENEXTRA_SZ, sizeof(TOKENEXTRA) == 20) +ct_assert(vp8_extra_bit_struct_sz, sizeof(vp8_extra_bit_struct) == 20) + +//add asserts for any offset that is not supported by assembly code +//add asserts for any size that is not supported by assembly code +/* + * return 0; + * } + */
diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c new file mode 100644 index 0000000..31ad56a --- /dev/null +++ b/vp8/encoder/bitstream.c
@@ -0,0 +1,1719 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "header.h" +#include "encodemv.h" +#include "entropymode.h" +#include "findnearmv.h" +#include "mcomp.h" +#include "systemdependent.h" +#include <assert.h> +#include <stdio.h> +#include "pragmas.h" +#include "vpx_mem/vpx_mem.h" +#include "bitstream.h" + +const int vp8cx_base_skip_false_prob[128] = +{ + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 251, 248, 244, 240, 236, 232, 229, 225, + 221, 217, 213, 208, 204, 199, 194, 190, + 187, 183, 179, 175, 172, 168, 164, 160, + 157, 153, 149, 145, 142, 138, 134, 130, + 127, 124, 120, 117, 114, 110, 107, 104, + 101, 98, 95, 92, 89, 86, 83, 80, + 77, 74, 71, 68, 65, 62, 59, 56, + 53, 50, 47, 44, 41, 38, 35, 32, + 30, 28, 26, 24, 22, 20, 18, 16, +}; +#ifdef VP8REF +#define __int64 long long +#endif + +#if defined(SECTIONBITS_OUTPUT) +unsigned __int64 Sectionbits[500]; +#endif + +#ifdef ENTROPY_STATS +int intra_mode_stats[10][10][10]; +static unsigned int tree_update_hist [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1] [2]; +extern unsigned int active_section; +#endif + +#ifdef MODE_STATS +int count_mb_seg[4] = { 0, 0, 0, 0 }; +#endif + +#if CONFIG_BIG_ENDIAN +# define make_endian_16(a) \ + (((unsigned int)(a & 0xff)) << 8) | (((unsigned int)(a & 0xff00)) >> 8) +# define make_endian_32(a) \ + (((unsigned int)(a & 0xff)) << 24) | (((unsigned int)(a & 0xff00)) << 8) | \ + (((unsigned int)(a & 0xff0000)) >> 8) | (((unsigned int)(a & 0xff000000)) >> 24) +#else +# define make_endian_16(a) a +# define make_endian_32(a) a +#endif + +static void update_mode( + vp8_writer *const w, + int n, + vp8_token tok [/* n */], + vp8_tree tree, + vp8_prob Pnew [/* n-1 */], + vp8_prob Pcur [/* n-1 */], + unsigned int bct [/* n-1 */] [2], + const unsigned int num_events[/* n */] +) +{ + unsigned int new_b = 0, old_b = 0; + int i = 0; + + vp8_tree_probs_from_distribution( + n--, tok, tree, + Pnew, bct, num_events, + 256, 1 + ); + + do + { + new_b += vp8_cost_branch(bct[i], Pnew[i]); + old_b += vp8_cost_branch(bct[i], Pcur[i]); + } + while (++i < n); + + if (new_b + (n << 8) < old_b) + { + int i = 0; + + vp8_write_bit(w, 1); + + do + { + const vp8_prob p = Pnew[i]; + + vp8_write_literal(w, Pcur[i] = p ? p : 1, 8); + } + while (++i < n); + } + else + vp8_write_bit(w, 0); +} + +static void update_mbintra_mode_probs(VP8_COMP *cpi) +{ + VP8_COMMON *const x = & cpi->common; + + vp8_writer *const w = & cpi->bc; + + { + vp8_prob Pnew [VP8_YMODES-1]; + unsigned int bct [VP8_YMODES-1] [2]; + + update_mode( + w, VP8_YMODES, vp8_ymode_encodings, vp8_ymode_tree, + Pnew, x->fc.ymode_prob, bct, (unsigned int *)cpi->ymode_count + ); + } + { + vp8_prob Pnew [VP8_UV_MODES-1]; + unsigned int bct [VP8_UV_MODES-1] [2]; + + update_mode( + w, VP8_UV_MODES, vp8_uv_mode_encodings, vp8_uv_mode_tree, + Pnew, x->fc.uv_mode_prob, bct, (unsigned int *)cpi->uv_mode_count + ); + } +} + +static void write_ymode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_ymode_tree, p, vp8_ymode_encodings + m); +} + +static void kfwrite_ymode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_kf_ymode_tree, p, vp8_kf_ymode_encodings + m); +} + +static void write_uv_mode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_uv_mode_tree, p, vp8_uv_mode_encodings + m); +} + + +static void write_bmode(vp8_writer *bc, int m, const vp8_prob *p) +{ + vp8_write_token(bc, vp8_bmode_tree, p, vp8_bmode_encodings + m); +} + +static void write_split(vp8_writer *bc, int x) +{ + vp8_write_token( + bc, vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + x + ); +} + +static const unsigned int norm[256] = +{ + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void pack_tokens_c(vp8_writer *w, const TOKENEXTRA *p, int xcount) +{ + const TOKENEXTRA *const stop = p + xcount; + unsigned int split; + unsigned int shift; + int count = w->count; + unsigned int range = w->range; + unsigned int lowvalue = w->lowvalue; + + while (p < stop) + { + const int t = p->Token; + vp8_token *const a = vp8_coef_encodings + t; + const vp8_extra_bit_struct *const b = vp8_extra_bits + t; + int i = 0; + const unsigned char *pp = p->context_tree; + int v = a->value; + int n = a->Len; + + if (p->skip_eob_node) + { + n--; + i = 2; + } + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = vp8_coef_tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + + + if (b->base_val) + { + const int e = p->Extra, L = b->Len; + + if (L) + { + const unsigned char *pp = b->prob; + int v = e >> 1; + int n = L; /* number of bits in v, assumed nonzero */ + int i = 0; + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = b->tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + } + + + { + + split = (range + 1) >> 1; + + if (e & 1) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + range <<= 1; + + if ((lowvalue & 0x80000000)) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + + } + + lowvalue <<= 1; + + if (!++count) + { + count = -8; + w->buffer[w->pos++] = (lowvalue >> 24); + lowvalue &= 0xffffff; + } + } + + } + + ++p; + } + + w->count = count; + w->lowvalue = lowvalue; + w->range = range; + +} + +static void write_partition_size(unsigned char *cx_data, int size) +{ + signed char csize; + + csize = size & 0xff; + *cx_data = csize; + csize = (size >> 8) & 0xff; + *(cx_data + 1) = csize; + csize = (size >> 16) & 0xff; + *(cx_data + 2) = csize; + +} + +static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data, int num_part, int *size) +{ + + int i; + unsigned char *ptr = cx_data; + unsigned int shift; + vp8_writer *w = &cpi->bc2; + *size = 3 * (num_part - 1); + ptr = cx_data + (*size); + + for (i = 0; i < num_part; i++) + { + vp8_start_encode(w, ptr); + { + unsigned int split; + int count = w->count; + unsigned int range = w->range; + unsigned int lowvalue = w->lowvalue; + int mb_row; + + for (mb_row = i; mb_row < cpi->common.mb_rows; mb_row += num_part) + { + TOKENEXTRA *p = cpi->tplist[mb_row].start; + TOKENEXTRA *stop = cpi->tplist[mb_row].stop; + + while (p < stop) + { + const int t = p->Token; + vp8_token *const a = vp8_coef_encodings + t; + const vp8_extra_bit_struct *const b = vp8_extra_bits + t; + int i = 0; + const unsigned char *pp = p->context_tree; + int v = a->value; + int n = a->Len; + + if (p->skip_eob_node) + { + n--; + i = 2; + } + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = vp8_coef_tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + + + if (b->base_val) + { + const int e = p->Extra, L = b->Len; + + if (L) + { + const unsigned char *pp = b->prob; + int v = e >> 1; + int n = L; /* number of bits in v, assumed nonzero */ + int i = 0; + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = b->tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + } + + { + split = (range + 1) >> 1; + + if (e & 1) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + range <<= 1; + + if ((lowvalue & 0x80000000)) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + + } + + lowvalue <<= 1; + + if (!++count) + { + count = -8; + w->buffer[w->pos++] = (lowvalue >> 24); + lowvalue &= 0xffffff; + } + } + + } + + ++p; + } + } + + w->count = count; + w->lowvalue = lowvalue; + w->range = range; + + } + + vp8_stop_encode(w); + *size += w->pos; + + if (i < (num_part - 1)) + { + write_partition_size(cx_data, w->pos); + cx_data += 3; + ptr += w->pos; + } + } +} + + +static void pack_mb_row_tokens_c(VP8_COMP *cpi, vp8_writer *w) +{ + + unsigned int split; + int count = w->count; + unsigned int range = w->range; + unsigned int lowvalue = w->lowvalue; + unsigned int shift; + int mb_row; + + for (mb_row = 0; mb_row < cpi->common.mb_rows; mb_row++) + { + TOKENEXTRA *p = cpi->tplist[mb_row].start; + TOKENEXTRA *stop = cpi->tplist[mb_row].stop; + + while (p < stop) + { + const int t = p->Token; + vp8_token *const a = vp8_coef_encodings + t; + const vp8_extra_bit_struct *const b = vp8_extra_bits + t; + int i = 0; + const unsigned char *pp = p->context_tree; + int v = a->value; + int n = a->Len; + + if (p->skip_eob_node) + { + n--; + i = 2; + } + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = vp8_coef_tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + + + if (b->base_val) + { + const int e = p->Extra, L = b->Len; + + if (L) + { + const unsigned char *pp = b->prob; + int v = e >> 1; + int n = L; /* number of bits in v, assumed nonzero */ + int i = 0; + + do + { + const int bb = (v >> --n) & 1; + split = 1 + (((range - 1) * pp[i>>1]) >> 8); + i = b->tree[i+bb]; + + if (bb) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + shift = norm[range]; + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + } + + w->buffer[w->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + } + while (n); + } + + { + split = (range + 1) >> 1; + + if (e & 1) + { + lowvalue += split; + range = range - split; + } + else + { + range = split; + } + + range <<= 1; + + if ((lowvalue & 0x80000000)) + { + int x = w->pos - 1; + + while (x >= 0 && w->buffer[x] == 0xff) + { + w->buffer[x] = (unsigned char)0; + x--; + } + + w->buffer[x] += 1; + + } + + lowvalue <<= 1; + + if (!++count) + { + count = -8; + w->buffer[w->pos++] = (lowvalue >> 24); + lowvalue &= 0xffffff; + } + } + + } + + ++p; + } + } + + w->count = count; + w->lowvalue = lowvalue; + w->range = range; + +} + +static void write_mv_ref +( + vp8_writer *w, MB_PREDICTION_MODE m, const vp8_prob *p +) +{ + + assert(NEARESTMV <= m && m <= SPLITMV); + + vp8_write_token(w, vp8_mv_ref_tree, p, VP8_MVREFENCODINGS + m); +} + +static void write_sub_mv_ref +( + vp8_writer *w, B_PREDICTION_MODE m, const vp8_prob *p +) +{ + assert(LEFT4X4 <= m && m <= NEW4X4); + + vp8_write_token(w, vp8_sub_mv_ref_tree, p, VP8_SUBMVREFENCODINGS + m); +} + +static void write_mv +( + vp8_writer *w, const MV *mv, const MV *ref, const MV_CONTEXT *mvc +) +{ + MV e; + e.row = mv->row - ref->row; + e.col = mv->col - ref->col; + + vp8_encode_motion_vector(w, &e, mvc); +} + +static void write_mb_features(vp8_writer *w, const MB_MODE_INFO *mi, const MACROBLOCKD *x) +{ + // Encode the MB segment id. + if (x->segmentation_enabled && x->update_mb_segmentation_map) + { + switch (mi->segment_id) + { + case 0: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[1]); + break; + case 1: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 1, x->mb_segment_tree_probs[1]); + break; + case 2: + vp8_write(w, 1, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[2]); + break; + case 3: + vp8_write(w, 1, x->mb_segment_tree_probs[0]); + vp8_write(w, 1, x->mb_segment_tree_probs[2]); + break; + + // TRAP.. This should not happen + default: + vp8_write(w, 0, x->mb_segment_tree_probs[0]); + vp8_write(w, 0, x->mb_segment_tree_probs[1]); + break; + } + } +} + + +static void pack_inter_mode_mvs(VP8_COMP *const cpi) +{ + VP8_COMMON *const pc = & cpi->common; + vp8_writer *const w = & cpi->bc; + const MV_CONTEXT *mvc = pc->fc.mvc; + + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + MODE_INFO *m = pc->mi, *ms; + const int mis = pc->mode_info_stride; + int mb_row = -1; + + int prob_last_coded; + int prob_gf_coded; + int prob_skip_false = 0; + ms = pc->mi - 1; + + // Calculate the probabilities to be used to code the reference frame based on actual useage this frame + if (!(cpi->prob_intra_coded = rf_intra * 255 / (rf_intra + rf_inter))) + cpi->prob_intra_coded = 1; + + prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (!prob_last_coded) + prob_last_coded = 1; + + prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (!prob_gf_coded) + prob_gf_coded = 1; + + +#ifdef ENTROPY_STATS + active_section = 1; +#endif + + if (pc->mb_no_coeff_skip) + { + prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count); + + if (prob_skip_false <= 1) + prob_skip_false = 1; + + if (prob_skip_false > 255) + prob_skip_false = 255; + + cpi->prob_skip_false = prob_skip_false; + vp8_write_literal(w, prob_skip_false, 8); + } + + vp8_write_literal(w, cpi->prob_intra_coded, 8); + vp8_write_literal(w, prob_last_coded, 8); + vp8_write_literal(w, prob_gf_coded, 8); + + update_mbintra_mode_probs(cpi); + + vp8_write_mvprobs(cpi); + + while (++mb_row < pc->mb_rows) + { + int mb_col = -1; + + while (++mb_col < pc->mb_cols) + { + const MB_MODE_INFO *const mi = & m->mbmi; + const MV_REFERENCE_FRAME rf = mi->ref_frame; + const MB_PREDICTION_MODE mode = mi->mode; + + MACROBLOCKD *xd = &cpi->mb.e_mbd; + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to MV values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16)) << 3; + xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3; + +#ifdef ENTROPY_STATS + active_section = 9; +#endif + + if (cpi->mb.e_mbd.update_mb_segmentation_map) + write_mb_features(w, mi, &cpi->mb.e_mbd); + + if (pc->mb_no_coeff_skip) + vp8_encode_bool(w, m->mbmi.mb_skip_coeff, prob_skip_false); + + if (rf == INTRA_FRAME) + { + vp8_write(w, 0, cpi->prob_intra_coded); +#ifdef ENTROPY_STATS + active_section = 6; +#endif + write_ymode(w, mode, pc->fc.ymode_prob); + + if (mode == B_PRED) + { + int j = 0; + + do + write_bmode(w, m->bmi[j].mode, pc->fc.bmode_prob); + + while (++j < 16); + } + + write_uv_mode(w, mi->uv_mode, pc->fc.uv_mode_prob); + } + else /* inter coded */ + { + MV best_mv; + vp8_prob mv_ref_p [VP8_MVREFS-1]; + + vp8_write(w, 1, cpi->prob_intra_coded); + + if (rf == LAST_FRAME) + vp8_write(w, 0, prob_last_coded); + else + { + vp8_write(w, 1, prob_last_coded); + vp8_write(w, (rf == GOLDEN_FRAME) ? 0 : 1, prob_gf_coded); + } + + { + MV n1, n2; + int ct[4]; + + vp8_find_near_mvs(xd, m, &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias); + vp8_mv_ref_probs(mv_ref_p, ct); + +#ifdef ENTROPY_STATS + accum_mv_refs(mode, ct); +#endif + + } + +#ifdef ENTROPY_STATS + active_section = 3; +#endif + + write_mv_ref(w, mode, mv_ref_p); + + switch (mode) /* new, split require MVs */ + { + case NEWMV: + +#ifdef ENTROPY_STATS + active_section = 5; +#endif + + write_mv(w, &mi->mv.as_mv, &best_mv, mvc); + break; + + case SPLITMV: + { + int j = 0; + +#ifdef MODE_STATS + ++count_mb_seg [mi->partitioning]; +#endif + + write_split(w, mi->partitioning); + + do + { + const B_MODE_INFO *const b = mi->partition_bmi + j; + const int *const L = vp8_mbsplits [mi->partitioning]; + int k = -1; /* first block in subset j */ + int mv_contz; + + while (j != L[++k]) + if (k >= 16) + assert(0); + + mv_contz = vp8_mv_cont + (&(vp8_left_bmi(m, k)->mv.as_mv), + &(vp8_above_bmi(m, k, mis)->mv.as_mv)); + write_sub_mv_ref(w, b->mode, vp8_sub_mv_ref_prob2 [mv_contz]); //pc->fc.sub_mv_ref_prob); + + if (b->mode == NEW4X4) + { +#ifdef ENTROPY_STATS + active_section = 11; +#endif + write_mv(w, &b->mv.as_mv, &best_mv, (const MV_CONTEXT *) mvc); + } + } + while (++j < mi->partition_count); + } + break; + default: + break; + } + } + + ++m; + } + + ++m; /* skip L prediction border */ + } +} + + +static void write_kfmodes(VP8_COMP *cpi) +{ + vp8_writer *const bc = & cpi->bc; + const VP8_COMMON *const c = & cpi->common; + /* const */ + MODE_INFO *m = c->mi; + + int mb_row = -1; + int prob_skip_false = 0; + + if (c->mb_no_coeff_skip) + { + prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count); + + if (prob_skip_false <= 1) + prob_skip_false = 1; + + if (prob_skip_false >= 255) + prob_skip_false = 255; + + cpi->prob_skip_false = prob_skip_false; + vp8_write_literal(bc, prob_skip_false, 8); + } + + while (++mb_row < c->mb_rows) + { + int mb_col = -1; + + while (++mb_col < c->mb_cols) + { + const int ym = m->mbmi.mode; + + if (cpi->mb.e_mbd.update_mb_segmentation_map) + write_mb_features(bc, &m->mbmi, &cpi->mb.e_mbd); + + if (c->mb_no_coeff_skip) + vp8_encode_bool(bc, m->mbmi.mb_skip_coeff, prob_skip_false); + + kfwrite_ymode(bc, ym, c->kf_ymode_prob); + + if (ym == B_PRED) + { + const int mis = c->mode_info_stride; + int i = 0; + + do + { + const B_PREDICTION_MODE A = vp8_above_bmi(m, i, mis)->mode; + const B_PREDICTION_MODE L = vp8_left_bmi(m, i)->mode; + const int bm = m->bmi[i].mode; + +#ifdef ENTROPY_STATS + ++intra_mode_stats [A] [L] [bm]; +#endif + + write_bmode(bc, bm, c->kf_bmode_prob [A] [L]); + } + while (++i < 16); + } + + write_uv_mode(bc, (m++)->mbmi.uv_mode, c->kf_uv_mode_prob); + } + + m++; // skip L prediction border + } +} +int vp8_estimate_entropy_savings(VP8_COMP *cpi) +{ + int i = 0; + int savings = 0; + + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + int new_intra, new_last, gf_last, oldtotal, newtotal; + int ref_frame_cost[MAX_REF_FRAMES]; + + vp8_clear_system_state(); //__asm emms; + + if (cpi->common.frame_type != KEY_FRAME) + { + if (!(new_intra = rf_intra * 255 / (rf_intra + rf_inter))) + new_intra = 1; + + new_last = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + gf_last = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + // new costs + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(new_intra); + ref_frame_cost[LAST_FRAME] = vp8_cost_one(new_intra) + + vp8_cost_zero(new_last); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(new_intra) + + vp8_cost_one(new_last) + + vp8_cost_zero(gf_last); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(new_intra) + + vp8_cost_one(new_last) + + vp8_cost_one(gf_last); + + newtotal = + rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + + rfct[LAST_FRAME] * ref_frame_cost[LAST_FRAME] + + rfct[GOLDEN_FRAME] * ref_frame_cost[GOLDEN_FRAME] + + rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; + + + // old costs + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_zero(cpi->prob_last_coded); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_zero(cpi->prob_gf_coded); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_one(cpi->prob_gf_coded); + + oldtotal = + rfct[INTRA_FRAME] * ref_frame_cost[INTRA_FRAME] + + rfct[LAST_FRAME] * ref_frame_cost[LAST_FRAME] + + rfct[GOLDEN_FRAME] * ref_frame_cost[GOLDEN_FRAME] + + rfct[ALTREF_FRAME] * ref_frame_cost[ALTREF_FRAME]; + + savings += (oldtotal - newtotal) / 256; + } + + + do + { + int j = 0; + + do + { + int k = 0; + + do + { + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [vp8_coef_tokens-1]; + //unsigned int branch_ct [vp8_coef_tokens-1] [2]; + + int t = 0; /* token/prob index */ + + vp8_tree_probs_from_distribution( + vp8_coef_tokens, vp8_coef_encodings, vp8_coef_tree, + cpi->frame_coef_probs [i][j][k], cpi->frame_branch_ct [i][j][k], cpi->coef_counts [i][j][k], + 256, 1 + ); + + do + { + const unsigned int *ct = cpi->frame_branch_ct [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + + const vp8_prob old = cpi->common.fc.coef_probs [i][j][k][t]; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + + const int old_b = vp8_cost_branch(ct, old); + const int new_b = vp8_cost_branch(ct, newp); + + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + + const int s = old_b - new_b - update_b; + + if (s > 0) + savings += s; + + + } + while (++t < vp8_coef_tokens - 1); + + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + + return savings; +} + +static void update_coef_probs(VP8_COMP *cpi) +{ + int i = 0; + vp8_writer *const w = & cpi->bc; + int savings = 0; + + vp8_clear_system_state(); //__asm emms; + + + do + { + int j = 0; + + do + { + int k = 0; + + do + { + //note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here. + /* at every context */ + + /* calc probs and branch cts for this frame only */ + //vp8_prob new_p [vp8_coef_tokens-1]; + //unsigned int branch_ct [vp8_coef_tokens-1] [2]; + + int t = 0; /* token/prob index */ + + //vp8_tree_probs_from_distribution( + // vp8_coef_tokens, vp8_coef_encodings, vp8_coef_tree, + // new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k], + // 256, 1 + // ); + + do + { + const unsigned int *ct = cpi->frame_branch_ct [i][j][k][t]; + const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t]; + + vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t; + const vp8_prob old = *Pold; + const vp8_prob upd = vp8_coef_update_probs [i][j][k][t]; + + const int old_b = vp8_cost_branch(ct, old); + const int new_b = vp8_cost_branch(ct, newp); + + const int update_b = 8 + + ((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8); + + const int s = old_b - new_b - update_b; + const int u = s > 0 ? 1 : 0; + + vp8_write(w, u, upd); + + +#ifdef ENTROPY_STATS + ++ tree_update_hist [i][j][k][t] [u]; +#endif + + if (u) + { + /* send/use new probability */ + + *Pold = newp; + vp8_write_literal(w, newp, 8); + + savings += s; + + } + + } + while (++t < vp8_coef_tokens - 1); + + /* Accum token counts for generation of default statistics */ +#ifdef ENTROPY_STATS + t = 0; + + do + { + context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t]; + } + while (++t < vp8_coef_tokens); + +#endif + + } + while (++k < PREV_COEF_CONTEXTS); + } + while (++j < COEF_BANDS); + } + while (++i < BLOCK_TYPES); + +} +#ifdef PACKET_TESTING +FILE *vpxlogc = 0; +#endif + +static void put_delta_q(vp8_writer *bc, int delta_q) +{ + if (delta_q != 0) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, abs(delta_q), 4); + + if (delta_q < 0) + vp8_write_bit(bc, 1); + else + vp8_write_bit(bc, 0); + } + else + vp8_write_bit(bc, 0); +} + +void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) +{ + int i, j; + VP8_HEADER oh; + VP8_COMMON *const pc = & cpi->common; + vp8_writer *const bc = & cpi->bc; + MACROBLOCKD *const xd = & cpi->mb.e_mbd; + int extra_bytes_packed = 0; + + unsigned char *cx_data = dest; + const int *mb_feature_data_bits; + + oh.show_frame = (int) pc->show_frame; + oh.type = (int)pc->frame_type; + oh.version = pc->version; + + mb_feature_data_bits = vp8_mb_feature_data_bits; + cx_data += 3; + +#if defined(SECTIONBITS_OUTPUT) + Sectionbits[active_section = 1] += sizeof(VP8_HEADER) * 8 * 256; +#endif + + //vp8_kf_default_bmode_probs() is called in vp8_setup_key_frame() once for each + //K frame before encode frame. pc->kf_bmode_prob doesn't get changed anywhere + //else. No need to call it again here. --yw + //vp8_kf_default_bmode_probs( pc->kf_bmode_prob); + + // every keyframe send startcode, width, height, scale factor, clamp and color type + if (oh.type == KEY_FRAME) + { + int w, h, hs, vs; + + // Start / synch code + cx_data[0] = 0x9D; + cx_data[1] = 0x01; + cx_data[2] = 0x2a; + + *((unsigned short *)(cx_data + 3)) = make_endian_16((pc->horiz_scale << 14) | pc->Width); + *((unsigned short *)(cx_data + 5)) = make_endian_16((pc->vert_scale << 14) | pc->Height); + + extra_bytes_packed = 7; + cx_data += extra_bytes_packed ; + + vp8_start_encode(bc, cx_data); + + // signal clr type + vp8_write_bit(bc, pc->clr_type); + vp8_write_bit(bc, pc->clamp_type); + + } + else + vp8_start_encode(bc, cx_data); + + + // Signal whether or not Segmentation is enabled + vp8_write_bit(bc, (xd->segmentation_enabled) ? 1 : 0); + + // Indicate which features are enabled + if (xd->segmentation_enabled) + { + // Signal whether or not the segmentation map is being updated. + vp8_write_bit(bc, (xd->update_mb_segmentation_map) ? 1 : 0); + vp8_write_bit(bc, (xd->update_mb_segmentation_data) ? 1 : 0); + + if (xd->update_mb_segmentation_data) + { + signed char Data; + + vp8_write_bit(bc, (xd->mb_segement_abs_delta) ? 1 : 0); + + // For each segmentation feature (Quant and loop filter level) + for (i = 0; i < MB_LVL_MAX; i++) + { + // For each of the segments + for (j = 0; j < MAX_MB_SEGMENTS; j++) + { + Data = xd->segment_feature_data[i][j]; + + // Frame level data + if (Data) + { + vp8_write_bit(bc, 1); + + if (Data < 0) + { + Data = - Data; + vp8_write_literal(bc, Data, mb_feature_data_bits[i]); + vp8_write_bit(bc, 1); + } + else + { + vp8_write_literal(bc, Data, mb_feature_data_bits[i]); + vp8_write_bit(bc, 0); + } + } + else + vp8_write_bit(bc, 0); + } + } + } + + if (xd->update_mb_segmentation_map) + { + // Write the probs used to decode the segment id for each macro block. + for (i = 0; i < MB_FEATURE_TREE_PROBS; i++) + { + int Data = xd->mb_segment_tree_probs[i]; + + if (Data != 255) + { + vp8_write_bit(bc, 1); + vp8_write_literal(bc, Data, 8); + } + else + vp8_write_bit(bc, 0); + } + } + } + + // Code to determine whether or not to update the scan order. + vp8_write_bit(bc, pc->filter_type); + vp8_write_literal(bc, pc->filter_level, 6); + vp8_write_literal(bc, pc->sharpness_level, 3); + + // Write out loop filter deltas applied at the MB level based on mode or ref frame (if they are enabled). + vp8_write_bit(bc, (xd->mode_ref_lf_delta_enabled) ? 1 : 0); + + if (xd->mode_ref_lf_delta_enabled) + { + // Do the deltas need to be updated + vp8_write_bit(bc, (xd->mode_ref_lf_delta_update) ? 1 : 0); + + if (xd->mode_ref_lf_delta_update) + { + int Data; + + // Send update + for (i = 0; i < MAX_REF_LF_DELTAS; i++) + { + Data = xd->ref_lf_deltas[i]; + + // Frame level data + if (Data) + { + vp8_write_bit(bc, 1); + + if (Data > 0) + { + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 0); // sign + } + else + { + Data = -Data; + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 1); // sign + } + } + else + vp8_write_bit(bc, 0); + } + + // Send update + for (i = 0; i < MAX_MODE_LF_DELTAS; i++) + { + Data = xd->mode_lf_deltas[i]; + + if (Data) + { + vp8_write_bit(bc, 1); + + if (Data > 0) + { + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 0); // sign + } + else + { + Data = -Data; + vp8_write_literal(bc, (Data & 0x3F), 6); + vp8_write_bit(bc, 1); // sign + } + } + else + vp8_write_bit(bc, 0); + } + } + } + + //signal here is multi token partition is enabled + vp8_write_literal(bc, pc->multi_token_partition, 2); + + // Frame Qbaseline quantizer index + vp8_write_literal(bc, pc->base_qindex, 7); + + // Transmit Dc, Second order and Uv quantizer delta information + put_delta_q(bc, pc->y1dc_delta_q); + put_delta_q(bc, pc->y2dc_delta_q); + put_delta_q(bc, pc->y2ac_delta_q); + put_delta_q(bc, pc->uvdc_delta_q); + put_delta_q(bc, pc->uvac_delta_q); + + // When there is a key frame all reference buffers are updated using the new key frame + if (pc->frame_type != KEY_FRAME) + { + // Should the GF or ARF be updated using the transmitted frame or buffer + vp8_write_bit(bc, pc->refresh_golden_frame); + vp8_write_bit(bc, pc->refresh_alt_ref_frame); + + // If not being updated from current frame should either GF or ARF be updated from another buffer + if (!pc->refresh_golden_frame) + vp8_write_literal(bc, pc->copy_buffer_to_gf, 2); + + if (!pc->refresh_alt_ref_frame) + vp8_write_literal(bc, pc->copy_buffer_to_arf, 2); + + // Indicate reference frame sign bias for Golden and ARF frames (always 0 for last frame buffer) + vp8_write_bit(bc, pc->ref_frame_sign_bias[GOLDEN_FRAME]); + vp8_write_bit(bc, pc->ref_frame_sign_bias[ALTREF_FRAME]); + } + + vp8_write_bit(bc, pc->refresh_entropy_probs); + + if (pc->frame_type != KEY_FRAME) + vp8_write_bit(bc, pc->refresh_last_frame); + +#ifdef ENTROPY_STATS + + if (pc->frame_type == INTER_FRAME) + active_section = 0; + else + active_section = 7; + +#endif + + vp8_clear_system_state(); //__asm emms; + + //************************************************ + // save a copy for later refresh + { + vpx_memcpy(&cpi->common.lfc, &cpi->common.fc, sizeof(cpi->common.fc)); + } + + update_coef_probs(cpi); + +#ifdef ENTROPY_STATS + active_section = 2; +#endif + + // Write out the mb_no_coeff_skip flag + vp8_write_bit(bc, pc->mb_no_coeff_skip); + + if (pc->frame_type == KEY_FRAME) + { + write_kfmodes(cpi); + +#ifdef ENTROPY_STATS + active_section = 8; +#endif + } + else + { + pack_inter_mode_mvs(cpi); + +#ifdef ENTROPY_STATS + active_section = 1; +#endif + } + + vp8_stop_encode(bc); + + + if (pc->multi_token_partition != ONE_PARTITION) + { + int num_part; + int asize; + num_part = 1 << pc->multi_token_partition; + + pack_tokens_into_partitions(cpi, cx_data + bc->pos, num_part, &asize); + + oh.first_partition_length_in_bytes = cpi->bc.pos; + + *size = cpi->bc.pos + VP8_HEADER_SIZE + asize + extra_bytes_packed; + } + else + { + vp8_start_encode(&cpi->bc2, cx_data + bc->pos); + + if (!cpi->b_multi_threaded) + pack_tokens(&cpi->bc2, cpi->tok, cpi->tok_count); + else + pack_mb_row_tokens(cpi, &cpi->bc2); + + vp8_stop_encode(&cpi->bc2); + oh.first_partition_length_in_bytes = cpi->bc.pos ; + *size = cpi->bc2.pos + cpi->bc.pos + VP8_HEADER_SIZE + extra_bytes_packed; + } + +#if CONFIG_BIG_ENDIAN + { + int v = (oh.first_partition_length_in_bytes << 5) | + (oh.show_frame << 4) | + (oh.version << 1) | + oh.type; + + v = make_endian_32(v); + vpx_memcpy(dest, &v, 3); + } +#else + vpx_memcpy(dest, &oh, 3); +#endif +} + +#ifdef ENTROPY_STATS +void print_tree_update_probs() +{ + int i, j, k, l; + FILE *f = fopen("context.c", "a"); + int Sum; + fprintf(f, "\n/* Update probabilities for token entropy tree. */\n\n"); + fprintf(f, "const vp8_prob tree_update_probs[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1] = {\n"); + + for (i = 0; i < BLOCK_TYPES; i++) + { + fprintf(f, " { \n"); + + for (j = 0; j < COEF_BANDS; j++) + { + fprintf(f, " {\n"); + + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + { + fprintf(f, " {"); + + for (l = 0; l < MAX_ENTROPY_TOKENS - 1; l++) + { + Sum = tree_update_hist[i][j][k][l][0] + tree_update_hist[i][j][k][l][1]; + + if (Sum > 0) + { + if (((tree_update_hist[i][j][k][l][0] * 255) / Sum) > 0) + fprintf(f, "%3ld, ", (tree_update_hist[i][j][k][l][0] * 255) / Sum); + else + fprintf(f, "%3ld, ", 1); + } + else + fprintf(f, "%3ld, ", 128); + } + + fprintf(f, "},\n"); + } + + fprintf(f, " },\n"); + } + + fprintf(f, " },\n"); + } + + fprintf(f, "};\n"); + fclose(f); +} +#endif
diff --git a/vp8/encoder/bitstream.h b/vp8/encoder/bitstream.h new file mode 100644 index 0000000..ee69f66 --- /dev/null +++ b/vp8/encoder/bitstream.h
@@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_BITSTREAM_H +#define __INC_BITSTREAM_H + +#if HAVE_ARMV7 +void vp8cx_pack_tokens_armv7(vp8_writer *w, const TOKENEXTRA *p, int xcount, + vp8_token *, + vp8_extra_bit_struct *, + const vp8_tree_index *); +void vp8cx_pack_tokens_into_partitions_armv7(VP8_COMP *, unsigned char *, int , int *, + vp8_token *, + vp8_extra_bit_struct *, + const vp8_tree_index *); +void vp8cx_pack_mb_row_tokens_armv7(VP8_COMP *cpi, vp8_writer *w, + vp8_token *, + vp8_extra_bit_struct *, + const vp8_tree_index *); +# define pack_tokens(a,b,c) \ + vp8cx_pack_tokens_armv7(a,b,c,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +# define pack_tokens_into_partitions(a,b,c,d) \ + vp8cx_pack_tokens_into_partitions_armv7(a,b,c,d,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +# define pack_mb_row_tokens(a,b) \ + vp8cx_pack_mb_row_tokens_armv7(a,b,vp8_coef_encodings,vp8_extra_bits,vp8_coef_tree) +#else +# define pack_tokens(a,b,c) pack_tokens_c(a,b,c) +# define pack_tokens_into_partitions(a,b,c,d) pack_tokens_into_partitions_c(a,b,c,d) +# define pack_mb_row_tokens(a,b) pack_mb_row_tokens_c(a,b) +#endif +#endif
diff --git a/vp8/encoder/block.h b/vp8/encoder/block.h new file mode 100644 index 0000000..cc4cbe0 --- /dev/null +++ b/vp8/encoder/block.h
@@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_BLOCK_H +#define __INC_BLOCK_H + +#include "onyx.h" +#include "blockd.h" +#include "entropymv.h" +#include "entropy.h" +#include "vpx_ports/mem.h" + +// motion search site +typedef struct +{ + MV mv; + int offset; +} search_site; + +typedef struct +{ + // 16 Y blocks, 4 U blocks, 4 V blocks each with 16 entries + short *src_diff; + short *coeff; + + // 16 Y blocks, 4 U blocks, 4 V blocks each with 16 entries + short(*quant)[4]; + short(*zbin)[4]; + short(*zrun_zbin_boost); + short(*round)[4]; + + // Zbin Over Quant value + short zbin_extra; + + unsigned char **base_src; + int src; + int src_stride; + +// MV enc_mv; + int force_empty; + +} BLOCK; + +typedef struct +{ + DECLARE_ALIGNED(16, short, src_diff[400]); // 16x16 Y 8x8 U 8x8 V 4x4 2nd Y + DECLARE_ALIGNED(16, short, coeff[400]); // 16x16 Y 8x8 U 8x8 V 4x4 2nd Y + + // 16 Y blocks, 4 U blocks, 4 V blocks, 1 DC 2nd order block each with 16 entries + BLOCK block[25]; + + YV12_BUFFER_CONFIG src; + + MACROBLOCKD e_mbd; + + search_site *ss; + int ss_count; + int searches_per_step; + + int errorperbit; + int sadperbit16; + int sadperbit4; + int errthresh; + int rddiv; + int rdmult; + + int mvcosts[2][MVvals+1]; + int *mvcost[2]; + int mvsadcosts[2][MVvals+1]; + int *mvsadcost[2]; + int mbmode_cost[2][MB_MODE_COUNT]; + int intra_uv_mode_cost[2][MB_MODE_COUNT]; + unsigned int bmode_costs[10][10][10]; + unsigned int inter_bmode_costs[B_MODE_COUNT]; + + // These define limits to motion vector components to prevent them from extending outside the UMV borders + int mv_col_min; + int mv_col_max; + int mv_row_min; + int mv_row_max; + + int vector_range; // Used to monitor limiting range of recent vectors to guide search. + int skip; + + int encode_breakout; + + unsigned char *active_ptr; + MV_CONTEXT *mvc; + + unsigned int token_costs[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens]; + int optimize; + + void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); + void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); + void (*short_fdct4x4rd)(short *input, short *output, int pitch); + void (*short_fdct8x4rd)(short *input, short *output, int pitch); + void (*vp8_short_fdct4x4_ptr)(short *input, short *output, int pitch); + void (*short_walsh4x4)(short *input, short *output, int pitch); + + void (*quantize_b)(BLOCK *b, BLOCKD *d); + void (*quantize_brd)(BLOCK *b, BLOCKD *d); + + + +} MACROBLOCK; + + +#endif
diff --git a/vp8/encoder/boolhuff.c b/vp8/encoder/boolhuff.c new file mode 100644 index 0000000..c101384 --- /dev/null +++ b/vp8/encoder/boolhuff.c
@@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "boolhuff.h" +#include "blockd.h" + + + +#if defined(SECTIONBITS_OUTPUT) +unsigned __int64 Sectionbits[500]; + +#endif + +#ifdef ENTROPY_STATS +unsigned int active_section = 0; +#endif + +const unsigned int vp8_prob_cost[256] = +{ + 2047, 2047, 1791, 1641, 1535, 1452, 1385, 1328, 1279, 1235, 1196, 1161, 1129, 1099, 1072, 1046, + 1023, 1000, 979, 959, 940, 922, 905, 889, 873, 858, 843, 829, 816, 803, 790, 778, + 767, 755, 744, 733, 723, 713, 703, 693, 684, 675, 666, 657, 649, 641, 633, 625, + 617, 609, 602, 594, 587, 580, 573, 567, 560, 553, 547, 541, 534, 528, 522, 516, + 511, 505, 499, 494, 488, 483, 477, 472, 467, 462, 457, 452, 447, 442, 437, 433, + 428, 424, 419, 415, 410, 406, 401, 397, 393, 389, 385, 381, 377, 373, 369, 365, + 361, 357, 353, 349, 346, 342, 338, 335, 331, 328, 324, 321, 317, 314, 311, 307, + 304, 301, 297, 294, 291, 288, 285, 281, 278, 275, 272, 269, 266, 263, 260, 257, + 255, 252, 249, 246, 243, 240, 238, 235, 232, 229, 227, 224, 221, 219, 216, 214, + 211, 208, 206, 203, 201, 198, 196, 194, 191, 189, 186, 184, 181, 179, 177, 174, + 172, 170, 168, 165, 163, 161, 159, 156, 154, 152, 150, 148, 145, 143, 141, 139, + 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, + 105, 103, 101, 99, 97, 95, 93, 92, 90, 88, 86, 84, 82, 81, 79, 77, + 75, 73, 72, 70, 68, 66, 65, 63, 61, 60, 58, 56, 55, 53, 51, 50, + 48, 46, 45, 43, 41, 40, 38, 37, 35, 33, 32, 30, 29, 27, 25, 24, + 22, 21, 19, 18, 16, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1, 1 +}; + +void vp8_start_encode(BOOL_CODER *br, unsigned char *source) +{ + + br->lowvalue = 0; + br->range = 255; + br->value = 0; + br->count = -24; + br->buffer = source; + br->pos = 0; +} + +void vp8_stop_encode(BOOL_CODER *br) +{ + int i; + + for (i = 0; i < 32; i++) + vp8_encode_bool(br, 0, 128); +} + +DECLARE_ALIGNED(16, static const unsigned int, norm[256]) = +{ + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void vp8_encode_bool(BOOL_CODER *br, int bit, int probability) +{ + unsigned int split; + int count = br->count; + unsigned int range = br->range; + unsigned int lowvalue = br->lowvalue; + register unsigned int shift; + +#ifdef ENTROPY_STATS +#if defined(SECTIONBITS_OUTPUT) + + if (bit) + Sectionbits[active_section] += vp8_prob_cost[255-probability]; + else + Sectionbits[active_section] += vp8_prob_cost[probability]; + +#endif +#endif + + split = 1 + (((range - 1) * probability) >> 8); + + range = split; + + if (bit) + { + lowvalue += split; + range = br->range - split; + } + + shift = norm[range]; + + range <<= shift; + count += shift; + + if (count >= 0) + { + int offset = shift - count; + + if ((lowvalue << (offset - 1)) & 0x80000000) + { + int x = br->pos - 1; + + while (x >= 0 && br->buffer[x] == 0xff) + { + br->buffer[x] = (unsigned char)0; + x--; + } + + br->buffer[x] += 1; + } + + br->buffer[br->pos++] = (lowvalue >> (24 - offset)); + lowvalue <<= offset; + shift = count; + lowvalue &= 0xffffff; + count -= 8 ; + } + + lowvalue <<= shift; + br->count = count; + br->lowvalue = lowvalue; + br->range = range; +} + +void vp8_encode_value(BOOL_CODER *br, int data, int bits) +{ + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + vp8_encode_bool(br, (1 & (data >> bit)), 0x80); + +}
diff --git a/vp8/encoder/boolhuff.h b/vp8/encoder/boolhuff.h new file mode 100644 index 0000000..0d929f0 --- /dev/null +++ b/vp8/encoder/boolhuff.h
@@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : boolhuff.h +* +* Description : Bool Coder header file. +* +****************************************************************************/ +#ifndef __INC_BOOLHUFF_H +#define __INC_BOOLHUFF_H + + +typedef struct +{ + unsigned int lowvalue; + unsigned int range; + unsigned int value; + int count; + unsigned int pos; + unsigned char *buffer; + + // Variables used to track bit costs without outputing to the bitstream + unsigned int measure_cost; + unsigned long bit_counter; +} BOOL_CODER; + +extern void vp8_start_encode(BOOL_CODER *bc, unsigned char *buffer); +extern void vp8_encode_bool(BOOL_CODER *bc, int x, int context); +extern void vp8_encode_value(BOOL_CODER *br, int data, int bits); +extern void vp8_stop_encode(BOOL_CODER *bc); +extern const unsigned int vp8_prob_cost[256]; + +#endif
diff --git a/vp8/encoder/dct.c b/vp8/encoder/dct.c new file mode 100644 index 0000000..5207e39 --- /dev/null +++ b/vp8/encoder/dct.c
@@ -0,0 +1,223 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> + + +static const short dct_matrix2[4][4] = +{ + { 23170, 30274, 23170, 12540 }, + { 23170, 12540, -23170, -30274 }, + { 23170, -12540, -23170, 30274 }, + { 23170, -30274, 23170, -12540 } +}; + +static const short dct_matrix1[4][4] = +{ + { 23170, 23170, 23170, 23170 }, + { 30274, 12540, -12540, -30274 }, + { 23170, -23170, -23170, 23170 }, + { 12540, -30274, 30274, -12540 } +}; + + +#define _1STSTAGESHIFT 14 +#define _1STSTAGEROUNDING (1<<( _1STSTAGESHIFT-1)) +#define _2NDSTAGESHIFT 16 +#define _2NDSTAGEROUNDING (1<<( _2NDSTAGESHIFT-1)) + +// using matrix multiply +void vp8_short_fdct4x4_c(short *input, short *output, int pitch) +{ + int i, j, k; + short temp[4][4]; + int sumtemp; + pitch >>= 1; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + sumtemp = 0; + + for (k = 0; k < 4; k++) + { + sumtemp += input[i*pitch+k] * dct_matrix2[k][j]; + + } + + temp[i][j] = (short)((sumtemp + _1STSTAGEROUNDING) >> _1STSTAGESHIFT); + } + } + + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + sumtemp = 0; + + for (k = 0; k < 4; k++) + { + sumtemp += dct_matrix1[i][ k] * temp[k][ j]; + } + + output[i*4+j] = (short)((sumtemp + _2NDSTAGEROUNDING) >> _2NDSTAGESHIFT); + } + } + +} + + +void vp8_short_fdct8x4_c(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_c(input, output, pitch); + vp8_short_fdct4x4_c(input + 4, output + 16, pitch); +} + + +static const signed short x_c1 = 60547; +static const signed short x_c2 = 46341; +static const signed short x_c3 = 25080; + +void vp8_fast_fdct4x4_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + int a2, b2, c2, d2; + short *ip = input; + + short *op = output; + int temp1, temp2; + + for (i = 0; i < 4; i++) + { + a1 = (ip[0] + ip[3]) * 2; + b1 = (ip[1] + ip[2]) * 2; + c1 = (ip[1] - ip[2]) * 2; + d1 = (ip[0] - ip[3]) * 2; + + temp1 = a1 + b1; + temp2 = a1 - b1; + + op[0] = ((temp1 * x_c2) >> 16) + temp1; + op[2] = ((temp2 * x_c2) >> 16) + temp2; + + temp1 = (c1 * x_c3) >> 16; + temp2 = ((d1 * x_c1) >> 16) + d1; + + op[1] = temp1 + temp2; + + temp1 = (d1 * x_c3) >> 16; + temp2 = ((c1 * x_c1) >> 16) + c1; + + op[3] = temp1 - temp2; + + ip += pitch / 2; + op += 4; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + + temp1 = a1 + b1; + temp2 = a1 - b1; + + a2 = ((temp1 * x_c2) >> 16) + temp1; + c2 = ((temp2 * x_c2) >> 16) + temp2; + + temp1 = (c1 * x_c3) >> 16; + temp2 = ((d1 * x_c1) >> 16) + d1; + + b2 = temp1 + temp2; + + temp1 = (d1 * x_c3) >> 16; + temp2 = ((c1 * x_c1) >> 16) + c1; + + d2 = temp1 - temp2; + + + op[0] = (a2 + 1) >> 1; + op[4] = (b2 + 1) >> 1; + op[8] = (c2 + 1) >> 1; + op[12] = (d2 + 1) >> 1; + + ip++; + op++; + } +} + +void vp8_fast_fdct8x4_c(short *input, short *output, int pitch) +{ + vp8_fast_fdct4x4_c(input, output, pitch); + vp8_fast_fdct4x4_c(input + 4, output + 16, pitch); +} + +void vp8_short_walsh4x4_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + int a2, b2, c2, d2; + short *ip = input; + short *op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[3]; + b1 = ip[1] + ip[2]; + c1 = ip[1] - ip[2]; + d1 = ip[0] - ip[3]; + + op[0] = a1 + b1; + op[1] = c1 + d1; + op[2] = a1 - b1; + op[3] = d1 - c1; + ip += pitch / 2; + op += 4; + } + + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + a2 = a1 + b1; + b2 = c1 + d1; + c2 = a1 - b1; + d2 = d1 - c1; + + a2 += (a2 > 0); + b2 += (b2 > 0); + c2 += (c2 > 0); + d2 += (d2 > 0); + + op[0] = (a2) >> 1; + op[4] = (b2) >> 1; + op[8] = (c2) >> 1; + op[12] = (d2) >> 1; + + ip++; + op++; + } +}
diff --git a/vp8/encoder/dct.h b/vp8/encoder/dct.h new file mode 100644 index 0000000..fb307cf --- /dev/null +++ b/vp8/encoder/dct.h
@@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_DCT_H +#define __INC_DCT_H + +#define prototype_fdct(sym) void (sym)(short *input, short *output, int pitch) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/dct_x86.h" +#endif + +#if ARCH_ARM +#include "arm/dct_arm.h" +#endif + +#ifndef vp8_fdct_short4x4 +#define vp8_fdct_short4x4 vp8_short_fdct4x4_c +#endif +extern prototype_fdct(vp8_fdct_short4x4); + +#ifndef vp8_fdct_short8x4 +#define vp8_fdct_short8x4 vp8_short_fdct8x4_c +#endif +extern prototype_fdct(vp8_fdct_short8x4); + +#ifndef vp8_fdct_fast4x4 +#define vp8_fdct_fast4x4 vp8_fast_fdct4x4_c +#endif +extern prototype_fdct(vp8_fdct_fast4x4); + +#ifndef vp8_fdct_fast8x4 +#define vp8_fdct_fast8x4 vp8_fast_fdct8x4_c +#endif +extern prototype_fdct(vp8_fdct_fast8x4); + +#ifndef vp8_fdct_walsh_short4x4 +#define vp8_fdct_walsh_short4x4 vp8_short_walsh4x4_c +#endif +extern prototype_fdct(vp8_fdct_walsh_short4x4); + +typedef prototype_fdct(*vp8_fdct_fn_t); +typedef struct +{ + vp8_fdct_fn_t short4x4; + vp8_fdct_fn_t short8x4; + vp8_fdct_fn_t fast4x4; + vp8_fdct_fn_t fast8x4; + vp8_fdct_fn_t walsh_short4x4; +} vp8_fdct_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define FDCT_INVOKE(ctx,fn) (ctx)->fn +#else +#define FDCT_INVOKE(ctx,fn) vp8_fdct_##fn +#endif + +#endif
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c new file mode 100644 index 0000000..a4e3772 --- /dev/null +++ b/vp8/encoder/encodeframe.c
@@ -0,0 +1,1223 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "encodemb.h" +#include "encodemv.h" +#include "common.h" +#include "onyx_int.h" +#include "extend.h" +#include "entropymode.h" +#include "quant_common.h" +#include "segmentation_common.h" +#include "setupintrarecon.h" +#include "encodeintra.h" +#include "reconinter.h" +#include "rdopt.h" +#include "pickinter.h" +#include "findnearmv.h" +#include "reconintra.h" +#include <stdio.h> +#include <limits.h> +#include "subpixel.h" +#include "vpx_ports/vpx_timer.h" + +#if CONFIG_RUNTIME_CPU_DETECT +#define RTCD(x) &cpi->common.rtcd.x +#define IF_RTCD(x) (x) +#else +#define RTCD(x) NULL +#define IF_RTCD(x) NULL +#endif +extern void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; + +extern void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex); +extern void vp8_auto_select_speed(VP8_COMP *cpi); +extern void vp8cx_init_mbrthread_data(VP8_COMP *cpi, + MACROBLOCK *x, + MB_ROW_COMP *mbr_ei, + int mb_row, + int count); +void vp8_build_block_offsets(MACROBLOCK *x); +void vp8_setup_block_ptrs(MACROBLOCK *x); +int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset); +int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t); + +#ifdef MODE_STATS +unsigned int inter_y_modes[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int inter_uv_modes[4] = {0, 0, 0, 0}; +unsigned int inter_b_modes[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int y_modes[5] = {0, 0, 0, 0, 0}; +unsigned int uv_modes[4] = {0, 0, 0, 0}; +unsigned int b_modes[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#endif + +// The first four entries are dummy values +static const int qrounding_factors[129] = +{ + 56, 56, 56, 56, 56, 56, 56, 56, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, +}; + +static const int qzbin_factors[129] = +{ + 64, 64, 64, 64, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, +}; + +void vp8cx_init_quantizer(VP8_COMP *cpi) +{ + int r, c; + int i; + int quant_val; + int Q; + + int zbin_boost[16] = {0, 0, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 44, 44}; + + for (Q = 0; Q < QINDEX_RANGE; Q++) + { + // dc values + quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); + cpi->Y1quant[Q][0][0] = (1 << 16) / quant_val; + cpi->Y1zbin[Q][0][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][0][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][0][0] = quant_val; + cpi->zrun_zbin_boost_y1[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc2quant(Q, cpi->common.y2dc_delta_q); + cpi->Y2quant[Q][0][0] = (1 << 16) / quant_val; + cpi->Y2zbin[Q][0][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][0][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][0][0] = quant_val; + cpi->zrun_zbin_boost_y2[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + quant_val = vp8_dc_uv_quant(Q, cpi->common.uvdc_delta_q); + cpi->UVquant[Q][0][0] = (1 << 16) / quant_val; + cpi->UVzbin[Q][0][0] = ((qzbin_factors[Q] * quant_val) + 64) >> 7;; + cpi->UVround[Q][0][0] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][0][0] = quant_val; + cpi->zrun_zbin_boost_uv[Q][0] = (quant_val * zbin_boost[0]) >> 7; + + // all the ac values = ; + for (i = 1; i < 16; i++) + { + int rc = vp8_default_zig_zag1d[i]; + r = (rc >> 2); + c = (rc & 3); + + quant_val = vp8_ac_yquant(Q); + cpi->Y1quant[Q][r][c] = (1 << 16) / quant_val; + cpi->Y1zbin[Q][r][c] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y1round[Q][r][c] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y1dequant[Q][r][c] = quant_val; + cpi->zrun_zbin_boost_y1[Q][i] = (quant_val * zbin_boost[i]) >> 7; + + quant_val = vp8_ac2quant(Q, cpi->common.y2ac_delta_q); + cpi->Y2quant[Q][r][c] = (1 << 16) / quant_val; + cpi->Y2zbin[Q][r][c] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->Y2round[Q][r][c] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.Y2dequant[Q][r][c] = quant_val; + cpi->zrun_zbin_boost_y2[Q][i] = (quant_val * zbin_boost[i]) >> 7; + + quant_val = vp8_ac_uv_quant(Q, cpi->common.uvac_delta_q); + cpi->UVquant[Q][r][c] = (1 << 16) / quant_val; + cpi->UVzbin[Q][r][c] = ((qzbin_factors[Q] * quant_val) + 64) >> 7; + cpi->UVround[Q][r][c] = (qrounding_factors[Q] * quant_val) >> 7; + cpi->common.UVdequant[Q][r][c] = quant_val; + cpi->zrun_zbin_boost_uv[Q][i] = (quant_val * zbin_boost[i]) >> 7; + } + } +} + +void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x) +{ + int i; + int QIndex; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = &xd->mbmi; + int zbin_extra; + + // Select the baseline MB Q index. + if (xd->segmentation_enabled) + { + // Abs Value + if (xd->mb_segement_abs_delta == SEGMENT_ABSDATA) + QIndex = xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + + // Delta Value + else + { + QIndex = cpi->common.base_qindex + xd->segment_feature_data[MB_LVL_ALT_Q][mbmi->segment_id]; + QIndex = (QIndex >= 0) ? ((QIndex <= MAXQ) ? QIndex : MAXQ) : 0; // Clamp to valid range + } + } + else + QIndex = cpi->common.base_qindex; + + // Y + zbin_extra = (cpi->common.Y1dequant[QIndex][0][1] * (cpi->zbin_over_quant + cpi->zbin_mode_boost)) >> 7; + + for (i = 0; i < 16; i++) + { + x->block[i].quant = cpi->Y1quant[QIndex]; + x->block[i].zbin = cpi->Y1zbin[QIndex]; + x->block[i].round = cpi->Y1round[QIndex]; + x->e_mbd.block[i].dequant = cpi->common.Y1dequant[QIndex]; + x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_y1[QIndex]; + x->block[i].zbin_extra = (short)zbin_extra; + } + + // UV + zbin_extra = (cpi->common.UVdequant[QIndex][0][1] * (cpi->zbin_over_quant + cpi->zbin_mode_boost)) >> 7; + + for (i = 16; i < 24; i++) + { + x->block[i].quant = cpi->UVquant[QIndex]; + x->block[i].zbin = cpi->UVzbin[QIndex]; + x->block[i].round = cpi->UVround[QIndex]; + x->e_mbd.block[i].dequant = cpi->common.UVdequant[QIndex]; + x->block[i].zrun_zbin_boost = cpi->zrun_zbin_boost_uv[QIndex]; + x->block[i].zbin_extra = (short)zbin_extra; + } + + // Y2 + zbin_extra = (cpi->common.Y2dequant[QIndex][0][1] * ((cpi->zbin_over_quant / 2) + cpi->zbin_mode_boost)) >> 7; + x->block[24].quant = cpi->Y2quant[QIndex]; + x->block[24].zbin = cpi->Y2zbin[QIndex]; + x->block[24].round = cpi->Y2round[QIndex]; + x->e_mbd.block[24].dequant = cpi->common.Y2dequant[QIndex]; + x->block[24].zrun_zbin_boost = cpi->zrun_zbin_boost_y2[QIndex]; + x->block[24].zbin_extra = (short)zbin_extra; +} + +void vp8cx_frame_init_quantizer(VP8_COMP *cpi) +{ + // vp8cx_init_quantizer() is first called in vp8_create_compressor(). A check is added here so that vp8cx_init_quantizer() is only called + // when these values are not all zero. + if (cpi->common.y1dc_delta_q | cpi->common.y2dc_delta_q | cpi->common.uvdc_delta_q | cpi->common.y2ac_delta_q | cpi->common.uvac_delta_q) + { + vp8cx_init_quantizer(cpi); + } + + // MB level quantizer setup + vp8cx_mb_init_quantizer(cpi, &cpi->mb); +} + + + +static +void encode_mb_row(VP8_COMP *cpi, + VP8_COMMON *cm, + int mb_row, + MACROBLOCK *x, + MACROBLOCKD *xd, + TOKENEXTRA **tp, + int *segment_counts, + int *totalrate) +{ + int i; + int recon_yoffset, recon_uvoffset; + int mb_col; + int recon_y_stride = cm->last_frame.y_stride; + int recon_uv_stride = cm->last_frame.uv_stride; + int seg_map_index = (mb_row * cpi->common.mb_cols); + + + // reset above block coeffs + xd->above_context[Y1CONTEXT] = cm->above_context[Y1CONTEXT]; + xd->above_context[UCONTEXT ] = cm->above_context[UCONTEXT ]; + xd->above_context[VCONTEXT ] = cm->above_context[VCONTEXT ]; + xd->above_context[Y2CONTEXT] = cm->above_context[Y2CONTEXT]; + + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + cpi->tplist[mb_row].start = *tp; + //printf("Main mb_row = %d\n", mb_row); + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((cm->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16) << 3); + xd->mb_to_bottom_edge = ((cm->mb_rows - 1 - mb_row) * 16) << 3; + + // Set up limit values for motion vectors used to prevent them extending outside the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); + + xd->dst.y_buffer = cm->new_frame.y_buffer + recon_yoffset; + xd->dst.u_buffer = cm->new_frame.u_buffer + recon_uvoffset; + xd->dst.v_buffer = cm->new_frame.v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + // Is segmentation enabled + // MB level adjutment to quantizer + if (xd->segmentation_enabled) + { + // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) + if (cpi->segmentation_map[seg_map_index+mb_col] <= 3) + xd->mbmi.segment_id = cpi->segmentation_map[seg_map_index+mb_col]; + else + xd->mbmi.segment_id = 0; + + vp8cx_mb_init_quantizer(cpi, x); + } + else + xd->mbmi.segment_id = 0; // Set to Segment 0 by default + + x->active_ptr = cpi->active_map + seg_map_index + mb_col; + + if (cm->frame_type == KEY_FRAME) + { + *totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp); +#ifdef MODE_STATS + y_modes[xd->mbmi.mode] ++; +#endif + } + else + { + *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset); + +#ifdef MODE_STATS + inter_y_modes[xd->mbmi.mode] ++; + + if (xd->mbmi.mode == SPLITMV) + { + int b; + + for (b = 0; b < xd->mbmi.partition_count; b++) + { + inter_b_modes[xd->mbmi.partition_bmi[b].mode] ++; + } + } + +#endif + + // Count of last ref frame 0,0 useage + if ((xd->mbmi.mode == ZEROMV) && (xd->mbmi.ref_frame == LAST_FRAME)) + cpi->inter_zz_count ++; + + // Special case code for cyclic refresh + // If cyclic update enabled then copy xd->mbmi.segment_id; (which may have been updated based on mode + // during vp8cx_encode_inter_macroblock()) back into the global sgmentation map + if (cpi->cyclic_refresh_mode_enabled && xd->segmentation_enabled) + { + cpi->segmentation_map[seg_map_index+mb_col] = xd->mbmi.segment_id; + + // If the block has been refreshed mark it as clean (the magnitude of the -ve influences how long it will be before we consider another refresh): + // Else if it was coded (last frame 0,0) and has not already been refreshed then mark it as a candidate for cleanup next time (marked 0) + // else mark it as dirty (1). + if (xd->mbmi.segment_id) + cpi->cyclic_refresh_map[seg_map_index+mb_col] = -1; + else if ((xd->mbmi.mode == ZEROMV) && (xd->mbmi.ref_frame == LAST_FRAME)) + { + if (cpi->cyclic_refresh_map[seg_map_index+mb_col] == 1) + cpi->cyclic_refresh_map[seg_map_index+mb_col] = 0; + } + else + cpi->cyclic_refresh_map[seg_map_index+mb_col] = 1; + + } + } + + cpi->tplist[mb_row].stop = *tp; + + xd->gf_active_ptr++; // Increment pointer into gf useage flags structure for next mb + + // store macroblock mode info into context array + vpx_memcpy(&xd->mode_info_context->mbmi, &xd->mbmi, sizeof(xd->mbmi)); + + for (i = 0; i < 16; i++) + vpx_memcpy(&xd->mode_info_context->bmi[i], &xd->block[i].bmi, sizeof(xd->block[i].bmi)); + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + + // Keep track of segment useage + segment_counts[xd->mbmi.segment_id] ++; + + // skip to next mb + xd->mode_info_context++; + + xd->above_context[Y1CONTEXT] += 4; + xd->above_context[UCONTEXT ] += 2; + xd->above_context[VCONTEXT ] += 2; + xd->above_context[Y2CONTEXT] ++; + cpi->current_mb_col_main = mb_col; + } + + //extend the recon for intra prediction + vp8_extend_mb_row( + &cm->new_frame, + xd->dst.y_buffer + 16, + xd->dst.u_buffer + 8, + xd->dst.v_buffer + 8); + + // this is to account for the border + xd->mode_info_context++; +} + + + + + +void vp8_encode_frame(VP8_COMP *cpi) +{ + int mb_row; + MACROBLOCK *const x = & cpi->mb; + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + + int i; + TOKENEXTRA *tp = cpi->tok; + int segment_counts[MAX_MB_SEGMENTS]; + int totalrate; + + if (cm->frame_type != KEY_FRAME) + { + if (cm->mcomp_filter_type == SIXTAP) + { + xd->subpixel_predict = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, sixtap4x4); + xd->subpixel_predict8x4 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, sixtap8x4); + xd->subpixel_predict8x8 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, sixtap8x8); + xd->subpixel_predict16x16 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, sixtap16x16); + } + else + { + xd->subpixel_predict = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, bilinear4x4); + xd->subpixel_predict8x4 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, bilinear8x4); + xd->subpixel_predict8x8 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, bilinear8x8); + xd->subpixel_predict16x16 = SUBPIX_INVOKE(&cpi->common.rtcd.subpix, bilinear16x16); + } + } + + //else // Key Frame + //{ + // For key frames make sure the intra ref frame probability value + // is set to "all intra" + //cpi->prob_intra_coded = 255; + //} + + + xd->gf_active_ptr = (signed char *)cm->gf_active_flags; // Point to base of GF active flags data structure + + x->vector_range = 32; + + // Count of MBs using the alternate Q if any + cpi->alt_qcount = 0; + + // Reset frame count of inter 0,0 motion vector useage. + cpi->inter_zz_count = 0; + + vpx_memset(segment_counts, 0, sizeof(segment_counts)); + + cpi->prediction_error = 0; + cpi->intra_error = 0; + cpi->skip_true_count = 0; + cpi->skip_false_count = 0; + +#if 0 + // Experimental code + cpi->frame_distortion = 0; + cpi->last_mb_distortion = 0; +#endif + + totalrate = 0; + + xd->mode_info = cm->mi - 1; + + xd->mode_info_context = cm->mi; + xd->mode_info_stride = cm->mode_info_stride; + + xd->frame_type = cm->frame_type; + + xd->frames_since_golden = cm->frames_since_golden; + xd->frames_till_alt_ref_frame = cm->frames_till_alt_ref_frame; + vp8_zero(cpi->MVcount); + // vp8_zero( Contexts) + vp8_zero(cpi->coef_counts); + + // reset intra mode contexts + if (cm->frame_type == KEY_FRAME) + vp8_init_mbmode_probs(cm); + + + vp8cx_frame_init_quantizer(cpi); + + if (cpi->compressor_speed == 2) + { + if (cpi->oxcf.cpu_used < 0) + cpi->Speed = -(cpi->oxcf.cpu_used); + else + vp8_auto_select_speed(cpi); + } + + vp8_initialize_rd_consts(cpi, vp8_dc_quant(cm->base_qindex, cm->y1dc_delta_q)); + //vp8_initialize_rd_consts( cpi, vp8_dc_quant(cpi->avg_frame_qindex, cm->y1dc_delta_q) ); + vp8cx_initialize_me_consts(cpi, cm->base_qindex); + //vp8cx_initialize_me_consts( cpi, cpi->avg_frame_qindex); + + // Copy data over into macro block data sturctures. + + x->src = * cpi->Source; + xd->pre = cm->last_frame; + xd->dst = cm->new_frame; + + // set up frame new frame for intra coded blocks + + vp8_setup_intra_recon(&cm->new_frame); + + vp8_build_block_offsets(x); + + vp8_setup_block_dptrs(&x->e_mbd); + + vp8_setup_block_ptrs(x); + + x->rddiv = cpi->RDDIV; + x->rdmult = cpi->RDMULT; + +#if 0 + // Experimental rd code + // 2 Pass - Possibly set Rdmult based on last frame distortion + this frame target bits or other metrics + // such as cpi->rate_correction_factor that indicate relative complexity. + /*if ( cpi->pass == 2 && (cpi->last_frame_distortion > 0) && (cpi->target_bits_per_mb > 0) ) + { + //x->rdmult = ((cpi->last_frame_distortion * 256)/cpi->common.MBs)/ cpi->target_bits_per_mb; + x->rdmult = (int)(cpi->RDMULT * cpi->rate_correction_factor); + } + else + x->rdmult = cpi->RDMULT; */ + //x->rdmult = (int)(cpi->RDMULT * pow( (cpi->rate_correction_factor * 2.0), 0.75 )); +#endif + + xd->mbmi.mode = DC_PRED; + xd->mbmi.uv_mode = DC_PRED; + + xd->left_context = cm->left_context; + + vp8_zero(cpi->count_mb_ref_frame_usage) + vp8_zero(cpi->ymode_count) + vp8_zero(cpi->uv_mode_count) + + x->mvc = cm->fc.mvc; + + // vp8_zero( entropy_stats) + { + ENTROPY_CONTEXT **p = cm->above_context; + const size_t L = cm->mb_cols; + + vp8_zero_array(p [Y1CONTEXT], L * 4) + vp8_zero_array(p [ UCONTEXT], L * 2) + vp8_zero_array(p [ VCONTEXT], L * 2) + vp8_zero_array(p [Y2CONTEXT], L) + } + + + { + struct vpx_usec_timer emr_timer; + vpx_usec_timer_start(&emr_timer); + + if (!cpi->b_multi_threaded) + { + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + + vp8_zero(cm->left_context) + + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + } + + cpi->tok_count = tp - cpi->tok; + + } + else + { +#if CONFIG_MULTITHREAD + vp8cx_init_mbrthread_data(cpi, x, cpi->mb_row_ei, 1, cpi->encoding_thread_count); + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row += (cpi->encoding_thread_count + 1)) + { + int i; + cpi->current_mb_col_main = -1; + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + if ((mb_row + i + 1) >= cm->mb_rows) + break; + + cpi->mb_row_ei[i].mb_row = mb_row + i + 1; + cpi->mb_row_ei[i].tp = cpi->tok + (mb_row + i + 1) * (cm->mb_cols * 16 * 24); + cpi->mb_row_ei[i].current_mb_col = -1; + //SetEvent(cpi->h_event_mbrencoding[i]); + sem_post(&cpi->h_event_mbrencoding[i]); + } + + vp8_zero(cm->left_context) + + tp = cpi->tok + mb_row * (cm->mb_cols * 16 * 24); + + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + + xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; + + if (mb_row < cm->mb_rows - 1) + //WaitForSingleObject(cpi->h_event_main, INFINITE); + sem_wait(&cpi->h_event_main); + } + + /* + for( ;mb_row<cm->mb_rows; mb_row ++) + { + vp8_zero( cm->left_context) + + tp = cpi->tok + mb_row * (cm->mb_cols * 16 * 24); + + encode_mb_row(cpi, cm, mb_row, x, xd, &tp, segment_counts, &totalrate); + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + + } + */ + cpi->tok_count = 0; + + for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) + { + cpi->tok_count += cpi->tplist[mb_row].stop - cpi->tplist[mb_row].start; + } + + if (xd->segmentation_enabled) + { + + int i, j; + + if (xd->segmentation_enabled) + { + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + for (j = 0; j < 4; j++) + segment_counts[j] += cpi->mb_row_ei[i].segment_counts[j]; + } + } + + } + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + totalrate += cpi->mb_row_ei[i].totalrate; + } + +#endif + + } + + vpx_usec_timer_mark(&emr_timer); + cpi->time_encode_mb_row += vpx_usec_timer_elapsed(&emr_timer); + + } + + + // Work out the segment probabilites if segmentation is enabled + if (xd->segmentation_enabled) + { + int tot_count; + int i; + + // Set to defaults + vpx_memset(xd->mb_segment_tree_probs, 255 , sizeof(xd->mb_segment_tree_probs)); + + tot_count = segment_counts[0] + segment_counts[1] + segment_counts[2] + segment_counts[3]; + + if (tot_count) + { + xd->mb_segment_tree_probs[0] = ((segment_counts[0] + segment_counts[1]) * 255) / tot_count; + + tot_count = segment_counts[0] + segment_counts[1]; + + if (tot_count > 0) + { + xd->mb_segment_tree_probs[1] = (segment_counts[0] * 255) / tot_count; + } + + tot_count = segment_counts[2] + segment_counts[3]; + + if (tot_count > 0) + xd->mb_segment_tree_probs[2] = (segment_counts[2] * 255) / tot_count; + + // Zero probabilities not allowed + for (i = 0; i < MB_FEATURE_TREE_PROBS; i ++) + { + if (xd->mb_segment_tree_probs[i] == 0) + xd->mb_segment_tree_probs[i] = 1; + } + } + } + + // 256 rate units to the bit + cpi->projected_frame_size = totalrate >> 8; // projected_frame_size in units of BYTES + + // Make a note of the percentage MBs coded Intra. + if (cm->frame_type == KEY_FRAME) + { + cpi->this_frame_percent_intra = 100; + } + else + { + int tot_modes; + + tot_modes = cpi->count_mb_ref_frame_usage[INTRA_FRAME] + + cpi->count_mb_ref_frame_usage[LAST_FRAME] + + cpi->count_mb_ref_frame_usage[GOLDEN_FRAME] + + cpi->count_mb_ref_frame_usage[ALTREF_FRAME]; + + if (tot_modes) + cpi->this_frame_percent_intra = cpi->count_mb_ref_frame_usage[INTRA_FRAME] * 100 / tot_modes; + + } + +#if 0 + { + int cnt = 0; + int flag[2] = {0, 0}; + + for (cnt = 0; cnt < MVPcount; cnt++) + { + if (cm->fc.pre_mvc[0][cnt] != cm->fc.mvc[0][cnt]) + { + flag[0] = 1; + vpx_memcpy(cm->fc.pre_mvc[0], cm->fc.mvc[0], MVPcount); + break; + } + } + + for (cnt = 0; cnt < MVPcount; cnt++) + { + if (cm->fc.pre_mvc[1][cnt] != cm->fc.mvc[1][cnt]) + { + flag[1] = 1; + vpx_memcpy(cm->fc.pre_mvc[1], cm->fc.mvc[1], MVPcount); + break; + } + } + + if (flag[0] || flag[1]) + vp8_build_component_cost_table(cpi->mb.mvcost, cpi->mb.mvsadcost, (const MV_CONTEXT *) cm->fc.mvc, flag); + } +#endif + + // Adjust the projected reference frame useage probability numbers to reflect + // what we have just seen. This may be usefull when we make multiple itterations + // of the recode loop rather than continuing to use values from the previous frame. + if ((cm->frame_type != KEY_FRAME) && !cm->refresh_alt_ref_frame && !cm->refresh_golden_frame) + { + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + if ((rf_intra + rf_inter) > 0) + { + cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); + + if (cpi->prob_intra_coded < 1) + cpi->prob_intra_coded = 1; + + if ((cm->frames_since_golden > 0) || cpi->source_alt_ref_active) + { + cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (cpi->prob_last_coded < 1) + cpi->prob_last_coded = 1; + + cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (cpi->prob_gf_coded < 1) + cpi->prob_gf_coded = 1; + } + } + } + +#if 0 + // Keep record of the total distortion this time around for future use + cpi->last_frame_distortion = cpi->frame_distortion; +#endif + +} +void vp8_setup_block_ptrs(MACROBLOCK *x) +{ + int r, c; + int i; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + x->block[r*4+c].src_diff = x->src_diff + r * 4 * 16 + c * 4; + } + } + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[16 + r*2+c].src_diff = x->src_diff + 256 + r * 4 * 8 + c * 4; + } + } + + + for (r = 0; r < 2; r++) + { + for (c = 0; c < 2; c++) + { + x->block[20 + r*2+c].src_diff = x->src_diff + 320 + r * 4 * 8 + c * 4; + } + } + + x->block[24].src_diff = x->src_diff + 384; + + + for (i = 0; i < 25; i++) + { + x->block[i].coeff = x->coeff + i * 16; + } +} + +void vp8_build_block_offsets(MACROBLOCK *x) +{ + int block = 0; + int br, bc; + + vp8_build_block_doffsets(&x->e_mbd); + + // y blocks + for (br = 0; br < 4; br++) + { + for (bc = 0; bc < 4; bc++) + { + BLOCK *this_block = &x->block[block]; + this_block->base_src = &x->src.y_buffer; + this_block->src_stride = x->src.y_stride; + this_block->src = 4 * br * this_block->src_stride + 4 * bc; + ++block; + } + } + + // u blocks + for (br = 0; br < 2; br++) + { + for (bc = 0; bc < 2; bc++) + { + BLOCK *this_block = &x->block[block]; + this_block->base_src = &x->src.u_buffer; + this_block->src_stride = x->src.uv_stride; + this_block->src = 4 * br * this_block->src_stride + 4 * bc; + ++block; + } + } + + // v blocks + for (br = 0; br < 2; br++) + { + for (bc = 0; bc < 2; bc++) + { + BLOCK *this_block = &x->block[block]; + this_block->base_src = &x->src.v_buffer; + this_block->src_stride = x->src.uv_stride; + this_block->src = 4 * br * this_block->src_stride + 4 * bc; + ++block; + } + } +} + +static void sum_intra_stats(VP8_COMP *cpi, MACROBLOCK *x) +{ + const MACROBLOCKD *xd = & x->e_mbd; + const MB_PREDICTION_MODE m = xd->mbmi.mode; + const MB_PREDICTION_MODE uvm = xd->mbmi.uv_mode; + +#ifdef MODE_STATS + const int is_key = cpi->common.frame_type == KEY_FRAME; + + ++ (is_key ? uv_modes : inter_uv_modes)[uvm]; + + if (m == B_PRED) + { + unsigned int *const bct = is_key ? b_modes : inter_b_modes; + + int b = 0; + + do + { + ++ bct[xd->block[b].bmi.mode]; + } + while (++b < 16); + } + +#endif + + ++cpi->ymode_count[m]; + ++cpi->uv_mode_count[uvm]; + +} +int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) +{ + int Error4x4, Error16x16, error_uv; + B_PREDICTION_MODE intra_bmodes[16]; + int rate4x4, rate16x16, rateuv; + int dist4x4, dist16x16, distuv; + int rate = 0; + int rate4x4_tokenonly = 0; + int rate16x16_tokenonly = 0; + int rateuv_tokenonly = 0; + int i; + + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->sf.RD || cpi->compressor_speed != 2) + { + Error4x4 = vp8_rd_pick_intra4x4mby_modes(cpi, x, &rate4x4, &rate4x4_tokenonly, &dist4x4); + + //save the b modes for possible later use + for (i = 0; i < 16; i++) + intra_bmodes[i] = x->e_mbd.block[i].bmi.mode; + + Error16x16 = vp8_rd_pick_intra16x16mby_mode(cpi, x, &rate16x16, &rate16x16_tokenonly, &dist16x16); + + error_uv = vp8_rd_pick_intra_mbuv_mode(cpi, x, &rateuv, &rateuv_tokenonly, &distuv); + + x->e_mbd.mbmi.mb_skip_coeff = (cpi->common.mb_no_coeff_skip) ? 1 : 0; + + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); + rate += rateuv; + + if (Error4x4 < Error16x16) + { + rate += rate4x4; + x->e_mbd.mbmi.mode = B_PRED; + + // get back the intra block modes + for (i = 0; i < 16; i++) + x->e_mbd.block[i].bmi.mode = intra_bmodes[i]; + + vp8_encode_intra4x4mby(IF_RTCD(&cpi->rtcd), x); + cpi->prediction_error += Error4x4 ; +#if 0 + // Experimental RD code + cpi->frame_distortion += dist4x4; +#endif + } + else + { + vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); + rate += rate16x16; + +#if 0 + // Experimental RD code + cpi->prediction_error += Error16x16; + cpi->frame_distortion += dist16x16; +#endif + } + + sum_intra_stats(cpi, x); + + vp8_tokenize_mb(cpi, &x->e_mbd, t); + } + else +#endif + { + + int rate2, distortion2; + MB_PREDICTION_MODE mode, best_mode = DC_PRED; + int this_rd; + Error16x16 = INT_MAX; + + for (mode = DC_PRED; mode <= TM_PRED; mode ++) + { + x->e_mbd.mbmi.mode = mode; + vp8_build_intra_predictors_mby_ptr(&x->e_mbd); + distortion2 = VARIANCE_INVOKE(&cpi->rtcd.variance, get16x16prederror)(x->src.y_buffer, x->src.y_stride, x->e_mbd.predictor, 16, 0x7fffffff); + rate2 = x->mbmode_cost[x->e_mbd.frame_type][mode]; + this_rd = RD_ESTIMATE(x->rdmult, x->rddiv, rate2, distortion2); + + if (Error16x16 > this_rd) + { + Error16x16 = this_rd; + best_mode = mode; + } + } + + vp8_pick_intra4x4mby_modes(IF_RTCD(&cpi->rtcd), x, &rate2, &distortion2); + + if (distortion2 == INT_MAX) + Error4x4 = INT_MAX; + else + Error4x4 = RD_ESTIMATE(x->rdmult, x->rddiv, rate2, distortion2); + + x->e_mbd.mbmi.mb_skip_coeff = (cpi->common.mb_no_coeff_skip) ? 1 : 0; + + if (Error4x4 < Error16x16) + { + x->e_mbd.mbmi.mode = B_PRED; + vp8_encode_intra4x4mby(IF_RTCD(&cpi->rtcd), x); + cpi->prediction_error += Error4x4; + } + else + { + x->e_mbd.mbmi.mode = best_mode; + vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); + cpi->prediction_error += Error16x16; + } + + vp8_pick_intra_mbuv_mode(x); + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); + sum_intra_stats(cpi, x); + vp8_tokenize_mb(cpi, &x->e_mbd, t); + } + + return rate; +} +#ifdef SPEEDSTATS +extern int cnt_pm; +#endif + +extern void vp8_fix_contexts(VP8_COMP *cpi, MACROBLOCKD *x); + +int vp8cx_encode_inter_macroblock +( + VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, + int recon_yoffset, int recon_uvoffset +) +{ + MACROBLOCKD *const xd = &x->e_mbd; + int inter_error; + int intra_error = 0; + int rate; + int distortion; + + x->skip = 0; + + if (xd->segmentation_enabled) + x->encode_breakout = cpi->segment_encode_breakout[xd->mbmi.segment_id]; + else + x->encode_breakout = cpi->oxcf.encode_breakout; + +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->sf.RD) + { + inter_error = vp8_rd_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, &distortion, &intra_error); + } + else +#endif + inter_error = vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, &distortion, &intra_error); + + + cpi->prediction_error += inter_error; + cpi->intra_error += intra_error; + +#if 0 + // Experimental RD code + cpi->frame_distortion += distortion; + cpi->last_mb_distortion = distortion; +#endif + + // MB level adjutment to quantizer setup + if (xd->segmentation_enabled || cpi->zbin_mode_boost_enabled) + { + // If cyclic update enabled + if (cpi->cyclic_refresh_mode_enabled) + { + // Clear segment_id back to 0 if not coded (last frame 0,0) + if ((xd->mbmi.segment_id == 1) && + ((xd->mbmi.ref_frame != LAST_FRAME) || (xd->mbmi.mode != ZEROMV))) + { + xd->mbmi.segment_id = 0; + } + } + + // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise + if (cpi->zbin_mode_boost_enabled) + { + if ((xd->mbmi.mode == ZEROMV) && (xd->mbmi.ref_frame != LAST_FRAME)) + cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; + else + cpi->zbin_mode_boost = 0; + } + + vp8cx_mb_init_quantizer(cpi, x); + } + + cpi->count_mb_ref_frame_usage[xd->mbmi.ref_frame] ++; + + if (xd->mbmi.ref_frame == INTRA_FRAME) + { + x->e_mbd.mbmi.mb_skip_coeff = (cpi->common.mb_no_coeff_skip) ? 1 : 0; + + vp8_encode_intra16x16mbuv(IF_RTCD(&cpi->rtcd), x); + + if (xd->mbmi.mode == B_PRED) + { + vp8_encode_intra4x4mby(IF_RTCD(&cpi->rtcd), x); + } + else + { + vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); + } + + sum_intra_stats(cpi, x); + } + else + { + MV best_ref_mv; + MV nearest, nearby; + int mdcounts[4]; + + vp8_find_near_mvs(xd, xd->mode_info_context, + &nearest, &nearby, &best_ref_mv, mdcounts, xd->mbmi.ref_frame, cpi->common.ref_frame_sign_bias); + + vp8_build_uvmvs(xd, cpi->common.full_pixel); + + // store motion vectors in our motion vector list + if (xd->mbmi.ref_frame == LAST_FRAME) + { + // Set up pointers for this macro block into the previous frame recon buffer + xd->pre.y_buffer = cpi->common.last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cpi->common.last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cpi->common.last_frame.v_buffer + recon_uvoffset; + } + else if (xd->mbmi.ref_frame == GOLDEN_FRAME) + { + // Set up pointers for this macro block into the golden frame recon buffer + xd->pre.y_buffer = cpi->common.golden_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cpi->common.golden_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cpi->common.golden_frame.v_buffer + recon_uvoffset; + } + else + { + // Set up pointers for this macro block into the alternate reference frame recon buffer + xd->pre.y_buffer = cpi->common.alt_ref_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cpi->common.alt_ref_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cpi->common.alt_ref_frame.v_buffer + recon_uvoffset; + } + + if (xd->mbmi.mode == SPLITMV) + { + int i; + + for (i = 0; i < 16; i++) + { + if (xd->block[i].bmi.mode == NEW4X4) + { + cpi->MVcount[0][mv_max+((xd->block[i].bmi.mv.as_mv.row - best_ref_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((xd->block[i].bmi.mv.as_mv.col - best_ref_mv.col) >> 1)]++; + } + } + } + else if (xd->mbmi.mode == NEWMV) + { + cpi->MVcount[0][mv_max+((xd->block[0].bmi.mv.as_mv.row - best_ref_mv.row) >> 1)]++; + cpi->MVcount[1][mv_max+((xd->block[0].bmi.mv.as_mv.col - best_ref_mv.col) >> 1)]++; + } + + if (!x->skip && !x->e_mbd.mbmi.force_no_skip) + { + vp8_encode_inter16x16(IF_RTCD(&cpi->rtcd), x); + + // Clear mb_skip_coeff if mb_no_coeff_skip is not set + if (!cpi->common.mb_no_coeff_skip) + xd->mbmi.mb_skip_coeff = 0; + + } + else + vp8_stuff_inter16x16(x); + } + + if (!x->skip) + vp8_tokenize_mb(cpi, xd, t); + else + { + if (cpi->common.mb_no_coeff_skip) + { + if (xd->mbmi.mode != B_PRED && xd->mbmi.mode != SPLITMV) + xd->mbmi.dc_diff = 0; + else + xd->mbmi.dc_diff = 1; + + xd->mbmi.mb_skip_coeff = 1; + cpi->skip_true_count ++; + vp8_fix_contexts(cpi, xd); + } + else + { + vp8_stuff_mb(cpi, xd, t); + xd->mbmi.mb_skip_coeff = 0; + cpi->skip_false_count ++; + } + } + + return rate; +}
diff --git a/vp8/encoder/encodeintra.c b/vp8/encoder/encodeintra.c new file mode 100644 index 0000000..403d020 --- /dev/null +++ b/vp8/encoder/encodeintra.c
@@ -0,0 +1,236 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "idct.h" +#include "quantize.h" +#include "reconintra.h" +#include "reconintra4x4.h" +#include "encodemb.h" +#include "invtrans.h" +#include "recon.h" +#include "dct.h" +#include "g_common.h" +#include "encodeintra.h" + +#define intra4x4ibias_rate 128 +#define intra4x4pbias_rate 256 + + +void vp8_update_mode_context(int *abmode, int *lbmode, int i, int best_mode) +{ + if (i < 12) + { + abmode[i+4] = best_mode; + } + + if ((i & 3) != 3) + { + lbmode[i+1] = best_mode; + } + +} +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif +void vp8_encode_intra4x4block(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x, BLOCK *be, BLOCKD *b, int best_mode) +{ + vp8_predict_intra4x4(b, best_mode, b->predictor); + + ENCODEMB_INVOKE(&rtcd->encodemb, subb)(be, b, 16); + + x->vp8_short_fdct4x4(be->src_diff, be->coeff, 32); + + x->quantize_b(be, b); + + x->e_mbd.mbmi.mb_skip_coeff &= (!b->eob); + + vp8_inverse_transform_b(IF_RTCD(&rtcd->common->idct), b, 32); + + RECON_INVOKE(&rtcd->common->recon, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); +} + +void vp8_encode_intra4x4block_rd(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x, BLOCK *be, BLOCKD *b, int best_mode) +{ + vp8_predict_intra4x4(b, best_mode, b->predictor); + + ENCODEMB_INVOKE(&rtcd->encodemb, subb)(be, b, 16); + + x->short_fdct4x4rd(be->src_diff, be->coeff, 32); + + x->quantize_brd(be, b); + + x->e_mbd.mbmi.mb_skip_coeff &= (!b->eob); + + IDCT_INVOKE(&rtcd->common->idct, idct16)(b->dqcoeff, b->diff, 32); + + RECON_INVOKE(&rtcd->common->recon, recon)(b->predictor, b->diff, *(b->base_dst) + b->dst, b->dst_stride); +} + +void vp8_encode_intra4x4mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *mb) +{ + int i; + + MACROBLOCKD *x = &mb->e_mbd; + vp8_intra_prediction_down_copy(x); + + for (i = 0; i < 16; i++) + { + BLOCK *be = &mb->block[i]; + BLOCKD *b = &x->block[i]; + + vp8_encode_intra4x4block(rtcd, mb, be, b, b->bmi.mode); + } + + return; +} + +void vp8_encode_intra16x16mby(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + int b; + + vp8_build_intra_predictors_mby_ptr(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride); + + vp8_transform_intra_mby(x); + + vp8_quantize_mby(x); + +#if !(CONFIG_REALTIME_ONLY) +#if 1 + + if (x->optimize && x->rddiv > 1) + vp8_optimize_mby(x, rtcd); + +#endif +#endif + + vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon16x16mby(IF_RTCD(&rtcd->common->recon), &x->e_mbd); + + // make sure block modes are set the way we want them for context updates + for (b = 0; b < 16; b++) + { + BLOCKD *d = &x->e_mbd.block[b]; + + switch (x->e_mbd.mbmi.mode) + { + + case DC_PRED: + d->bmi.mode = B_DC_PRED; + break; + case V_PRED: + d->bmi.mode = B_VE_PRED; + break; + case H_PRED: + d->bmi.mode = B_HE_PRED; + break; + case TM_PRED: + d->bmi.mode = B_TM_PRED; + break; + default: + d->bmi.mode = B_DC_PRED; + break; + + } + } +} + +void vp8_encode_intra16x16mbyrd(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + int b; + + vp8_build_intra_predictors_mby_ptr(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride); + + vp8_transform_intra_mbyrd(x); + + x->e_mbd.mbmi.mb_skip_coeff = 1; + + vp8_quantize_mbyrd(x); + + + vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon16x16mby(IF_RTCD(&rtcd->common->recon), &x->e_mbd); + + // make sure block modes are set the way we want them for context updates + for (b = 0; b < 16; b++) + { + BLOCKD *d = &x->e_mbd.block[b]; + + switch (x->e_mbd.mbmi.mode) + { + + case DC_PRED: + d->bmi.mode = B_DC_PRED; + break; + case V_PRED: + d->bmi.mode = B_VE_PRED; + break; + case H_PRED: + d->bmi.mode = B_HE_PRED; + break; + case TM_PRED: + d->bmi.mode = B_TM_PRED; + break; + default: + d->bmi.mode = B_DC_PRED; + break; + + } + } +} + +void vp8_encode_intra16x16mbuv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_intra_predictors_mbuv(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + + vp8_transform_mbuv(x); + + vp8_quantize_mbuv(x); + +#if !(CONFIG_REALTIME_ONLY) +#if 1 + + if (x->optimize && x->rddiv > 1) + vp8_optimize_mbuv(x, rtcd); + +#endif +#endif + + vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon_intra_mbuv(IF_RTCD(&rtcd->common->recon), &x->e_mbd); +} + +void vp8_encode_intra16x16mbuvrd(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_intra_predictors_mbuv(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + + vp8_transform_mbuvrd(x); + + vp8_quantize_mbuvrd(x); + + + + vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon_intra_mbuv(IF_RTCD(&rtcd->common->recon), &x->e_mbd); +}
diff --git a/vp8/encoder/encodeintra.h b/vp8/encoder/encodeintra.h new file mode 100644 index 0000000..4a43ab2 --- /dev/null +++ b/vp8/encoder/encodeintra.h
@@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef _ENCODEINTRA_H_ +#define _ENCODEINTRA_H_ +#include "onyx_int.h" + +void vp8_encode_intra16x16mby(const VP8_ENCODER_RTCD *, MACROBLOCK *x); +void vp8_encode_intra16x16mbuv(const VP8_ENCODER_RTCD *, MACROBLOCK *x); +void vp8_encode_intra4x4mby(const VP8_ENCODER_RTCD *, MACROBLOCK *mb); +void vp8_encode_intra4x4block(const VP8_ENCODER_RTCD *, MACROBLOCK *x, BLOCK *be, BLOCKD *b, int best_mode); +void vp8_update_mode_context(int *abmode, int *lbmode, int i, int best_mode); +void vp8_encode_intra4x4block_rd(const VP8_ENCODER_RTCD *, MACROBLOCK *x, BLOCK *be, BLOCKD *b, int best_mode); +void vp8_encode_intra16x16mbyrd(const VP8_ENCODER_RTCD *, MACROBLOCK *x); +void vp8_encode_intra16x16mbuvrd(const VP8_ENCODER_RTCD *, MACROBLOCK *x); + +#endif
diff --git a/vp8/encoder/encodemb.c b/vp8/encoder/encodemb.c new file mode 100644 index 0000000..d825133 --- /dev/null +++ b/vp8/encoder/encodemb.c
@@ -0,0 +1,1129 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "encodemb.h" +#include "reconinter.h" +#include "quantize.h" +#include "invtrans.h" +#include "recon.h" +#include "reconintra.h" +#include "dct.h" +#include "vpx_mem/vpx_mem.h" + +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif +void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *src_ptr = (*(be->base_src) + be->src); + short *diff_ptr = be->src_diff; + unsigned char *pred_ptr = bd->predictor; + int src_stride = be->src_stride; + + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + diff_ptr[c] = src_ptr[c] - pred_ptr[c]; + } + + diff_ptr += pitch; + pred_ptr += pitch; + src_ptr += src_stride; + } +} + +void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride) +{ + short *udiff = diff + 256; + short *vdiff = diff + 320; + unsigned char *upred = pred + 256; + unsigned char *vpred = pred + 320; + + int r, c; + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + udiff[c] = usrc[c] - upred[c]; + } + + udiff += 8; + upred += 8; + usrc += stride; + } + + for (r = 0; r < 8; r++) + { + for (c = 0; c < 8; c++) + { + vdiff[c] = vsrc[c] - vpred[c]; + } + + vdiff += 8; + vpred += 8; + vsrc += stride; + } +} + +void vp8_subtract_mby_c(short *diff, unsigned char *src, unsigned char *pred, int stride) +{ + int r, c; + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + diff[c] = src[c] - pred[c]; + } + + diff += 16; + pred += 16; + src += stride; + } +} + +static void vp8_subtract_mb(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride); + ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); +} + +void vp8_build_dcblock(MACROBLOCK *x) +{ + short *src_diff_ptr = &x->src_diff[384]; + int i; + + for (i = 0; i < 16; i++) + { + src_diff_ptr[i] = x->coeff[i * 16]; + } +} + +void vp8_transform_mbuv(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i += 2) + { + x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16); + } +} + +void vp8_transform_mbuvrd(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i += 2) + { + x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16); + } +} + +void vp8_transform_intra_mby(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + vp8_build_dcblock(x); + + // do 2nd order transform on the dc block + x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8); + +} + +void vp8_transform_intra_mbyrd(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + vp8_build_dcblock(x); + + // do 2nd order transform on the dc block + x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8); +} + +void vp8_transform_mb(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + if (x->e_mbd.mbmi.mode != SPLITMV) + vp8_build_dcblock(x); + + for (i = 16; i < 24; i += 2) + { + x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16); + } + + // do 2nd order transform on the dc block + if (x->e_mbd.mbmi.mode != SPLITMV) + x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8); + +} + +void vp8_transform_mby(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->vp8_short_fdct8x4(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + if (x->e_mbd.mbmi.mode != SPLITMV) + { + vp8_build_dcblock(x); + x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8); + } +} + +void vp8_transform_mbrd(MACROBLOCK *x) +{ + int i; + + for (i = 0; i < 16; i += 2) + { + x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 32); + } + + // build dc block from 16 y dc values + if (x->e_mbd.mbmi.mode != SPLITMV) + vp8_build_dcblock(x); + + for (i = 16; i < 24; i += 2) + { + x->short_fdct8x4rd(&x->block[i].src_diff[0], &x->block[i].coeff[0], 16); + } + + // do 2nd order transform on the dc block + if (x->e_mbd.mbmi.mode != SPLITMV) + x->short_walsh4x4(&x->block[24].src_diff[0], &x->block[24].coeff[0], 8); +} + +void vp8_stuff_inter16x16(MACROBLOCK *x) +{ + vp8_build_inter_predictors_mb_s(&x->e_mbd); + /* + // recon = copy from predictors to destination + { + BLOCKD *b = &x->e_mbd.block[0]; + unsigned char *pred_ptr = b->predictor; + unsigned char *dst_ptr = *(b->base_dst) + b->dst; + int stride = b->dst_stride; + + int i; + for(i=0;i<16;i++) + vpx_memcpy(dst_ptr+i*stride,pred_ptr+16*i,16); + + b = &x->e_mbd.block[16]; + pred_ptr = b->predictor; + dst_ptr = *(b->base_dst) + b->dst; + stride = b->dst_stride; + + for(i=0;i<8;i++) + vpx_memcpy(dst_ptr+i*stride,pred_ptr+8*i,8); + + b = &x->e_mbd.block[20]; + pred_ptr = b->predictor; + dst_ptr = *(b->base_dst) + b->dst; + stride = b->dst_stride; + + for(i=0;i<8;i++) + vpx_memcpy(dst_ptr+i*stride,pred_ptr+8*i,8); + } + */ +} + +#if !(CONFIG_REALTIME_ONLY) +extern const TOKENEXTRA vp8_dct_value_tokens[DCT_MAX_VALUE*2]; +extern const TOKENEXTRA *vp8_dct_value_tokens_ptr; +extern int vp8_dct_value_cost[DCT_MAX_VALUE*2]; +extern int *vp8_dct_value_cost_ptr; + +static int cost_coeffs(MACROBLOCK *mb, BLOCKD *b, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int c = !type; /* start at coef 0, unless Y with Y2 */ + int eob = b->eob; + int pt ; /* surrounding block/prev coef predictor */ + int cost = 0; + short *qcoeff_ptr = b->qcoeff; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + +# define QC( I) ( qcoeff_ptr [vp8_default_zig_zag1d[I]] ) + + for (; c < eob; c++) + { + int v = QC(c); + int t = vp8_dct_value_tokens_ptr[v].Token; + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [t]; + cost += vp8_dct_value_cost_ptr[v]; + pt = vp8_prev_token_class[t]; + } + +# undef QC + + if (c < 16) + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [DCT_EOB_TOKEN]; + + return cost; +} + +static int mbycost_coeffs(MACROBLOCK *mb) +{ + int cost = 0; + int b; + TEMP_CONTEXT t; + int type = 0; + + MACROBLOCKD *x = &mb->e_mbd; + + vp8_setup_temp_context(&t, x->above_context[Y1CONTEXT], x->left_context[Y1CONTEXT], 4); + + if (x->mbmi.mode == SPLITMV) + type = 3; + + for (b = 0; b < 16; b++) + cost += cost_coeffs(mb, x->block + b, type, + t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + + return cost; +} + +#define RDFUNC(RM,DM,R,D,target_rd) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) + +void vp8_optimize_b(MACROBLOCK *x, int i, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, const VP8_ENCODER_RTCD *rtcd) +{ + BLOCK *b = &x->block[i]; + BLOCKD *bd = &x->e_mbd.block[i]; + short *dequant_ptr = &bd->dequant[0][0]; + int nzpos[16] = {0}; + short saved_qcoefs[16]; + short saved_dqcoefs[16]; + int baserate, baseerror, baserd; + int rate, error, thisrd; + int k; + int nzcoefcount = 0; + int nc, bestnc = 0; + int besteob; + + // count potential coefficient to be optimized + for (k = !type; k < 16; k++) + { + int qcoef = abs(bd->qcoeff[k]); + int coef = abs(b->coeff[k]); + int dq = dequant_ptr[k]; + + if (qcoef && (qcoef * dq > coef) && (qcoef * dq < coef + dq)) + { + nzpos[nzcoefcount] = k; + nzcoefcount++; + } + } + + // if nothing here, do nothing for this block. + if (!nzcoefcount) + { + *a = *l = (bd->eob != !type); + return; + } + + // save a copy of quantized coefficients + vpx_memcpy(saved_qcoefs, bd->qcoeff, 32); + vpx_memcpy(saved_dqcoefs, bd->dqcoeff, 32); + + besteob = bd->eob; + baserate = cost_coeffs(x, bd, type, a, l); + baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2; + baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100); + + for (nc = 1; nc < (1 << nzcoefcount); nc++) + { + //reset coefficients + vpx_memcpy(bd->qcoeff, saved_qcoefs, 32); + vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32); + + for (k = 0; k < nzcoefcount; k++) + { + int pos = nzpos[k]; + + if ((nc & (1 << k))) + { + int cur_qcoef = bd->qcoeff[pos]; + + if (cur_qcoef < 0) + { + bd->qcoeff[pos]++; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + else + { + bd->qcoeff[pos]--; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + } + } + + { + int eob = -1; + int rc; + int m; + + for (m = 0; m < 16; m++) + { + rc = vp8_default_zig_zag1d[m]; + + if (bd->qcoeff[rc]) + eob = m; + } + + bd->eob = eob + 1; + } + + rate = cost_coeffs(x, bd, type, a, l); + error = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2; + thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100); + + if (thisrd < baserd) + { + baserd = thisrd; + bestnc = nc; + besteob = bd->eob; + } + } + + //reset coefficients + vpx_memcpy(bd->qcoeff, saved_qcoefs, 32); + vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32); + + if (bestnc) + { + for (k = 0; k < nzcoefcount; k++) + { + int pos = nzpos[k]; + + if (bestnc & (1 << k)) + { + int cur_qcoef = bd->qcoeff[pos]; + + if (cur_qcoef < 0) + { + bd->qcoeff[pos]++; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + else + { + bd->qcoeff[pos]--; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + } + } + +#if 0 + { + int eob = -1; + int rc; + int m; + + for (m = 0; m < 16; m++) + { + rc = vp8_default_zig_zag1d[m]; + + if (bd->qcoeff[rc]) + eob = m; + } + + bd->eob = eob + 1; + } +#endif + } + +#if 1 + bd->eob = besteob; +#endif +#if 0 + { + int eob = -1; + int rc; + int m; + + for (m = 0; m < 16; m++) + { + rc = vp8_default_zig_zag1d[m]; + + if (bd->qcoeff[rc]) + eob = m; + } + + bd->eob = eob + 1; + } + +#endif + *a = *l = (bd->eob != !type); + return; +} + +void vp8_optimize_bplus(MACROBLOCK *x, int i, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, const VP8_ENCODER_RTCD *rtcd) +{ + BLOCK *b = &x->block[i]; + BLOCKD *bd = &x->e_mbd.block[i]; + short *dequant_ptr = &bd->dequant[0][0]; + int nzpos[16] = {0}; + short saved_qcoefs[16]; + short saved_dqcoefs[16]; + int baserate, baseerror, baserd; + int rate, error, thisrd; + int k; + int nzcoefcount = 0; + int nc, bestnc = 0; + int besteob; + + // count potential coefficient to be optimized + for (k = !type; k < 16; k++) + { + int qcoef = abs(bd->qcoeff[k]); + int coef = abs(b->coeff[k]); + int dq = dequant_ptr[k]; + + if (qcoef && (qcoef * dq < coef) && (coef < (qcoef * dq + dq))) + { + nzpos[nzcoefcount] = k; + nzcoefcount++; + } + } + + // if nothing here, do nothing for this block. + if (!nzcoefcount) + { + //do not update context, we need do the other half. + //*a = *l = (bd->eob != !type); + return; + } + + // save a copy of quantized coefficients + vpx_memcpy(saved_qcoefs, bd->qcoeff, 32); + vpx_memcpy(saved_dqcoefs, bd->dqcoeff, 32); + + besteob = bd->eob; + baserate = cost_coeffs(x, bd, type, a, l); + baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2; + baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100); + + for (nc = 1; nc < (1 << nzcoefcount); nc++) + { + //reset coefficients + vpx_memcpy(bd->qcoeff, saved_qcoefs, 32); + vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32); + + for (k = 0; k < nzcoefcount; k++) + { + int pos = nzpos[k]; + + if ((nc & (1 << k))) + { + int cur_qcoef = bd->qcoeff[pos]; + + if (cur_qcoef < 0) + { + bd->qcoeff[pos]--; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + else + { + bd->qcoeff[pos]++; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + } + } + + { + int eob = -1; + int rc; + int m; + + for (m = 0; m < 16; m++) + { + rc = vp8_default_zig_zag1d[m]; + + if (bd->qcoeff[rc]) + eob = m; + } + + bd->eob = eob + 1; + } + + rate = cost_coeffs(x, bd, type, a, l); + error = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 2; + thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100); + + if (thisrd < baserd) + { + baserd = thisrd; + bestnc = nc; + besteob = bd->eob; + } + } + + //reset coefficients + vpx_memcpy(bd->qcoeff, saved_qcoefs, 32); + vpx_memcpy(bd->dqcoeff, saved_dqcoefs, 32); + + if (bestnc) + { + for (k = 0; k < nzcoefcount; k++) + { + int pos = nzpos[k]; + + if (bestnc & (1 << k)) + { + int cur_qcoef = bd->qcoeff[pos]; + + if (cur_qcoef < 0) + { + bd->qcoeff[pos]++; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + else + { + bd->qcoeff[pos]--; + bd->dqcoeff[pos] = bd->qcoeff[pos] * dequant_ptr[pos]; + } + } + } + } + + bd->eob = besteob; + //do not update context, we need do the other half. + //*a = *l = (bd->eob != !type); + return; +} + +void vp8_optimize_y2b(MACROBLOCK *x, int i, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l, const VP8_ENCODER_RTCD *rtcd) +{ + + BLOCK *b = &x->block[i]; + BLOCKD *bd = &x->e_mbd.block[i]; + short *dequant_ptr = &bd->dequant[0][0]; + + int baserate, baseerror, baserd; + int rate, error, thisrd; + int k; + + if (bd->eob == 0) + return; + + baserate = cost_coeffs(x, bd, type, a, l); + baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 4; + baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100); + + for (k = 0; k < 16; k++) + { + int cur_qcoef = bd->qcoeff[k]; + + if (!cur_qcoef) + continue; + + if (cur_qcoef < 0) + { + bd->qcoeff[k]++; + bd->dqcoeff[k] = bd->qcoeff[k] * dequant_ptr[k]; + } + else + { + bd->qcoeff[k]--; + bd->dqcoeff[k] = bd->qcoeff[k] * dequant_ptr[k]; + } + + if (bd->qcoeff[k] == 0) + { + int eob = -1; + int rc; + int l; + + for (l = 0; l < 16; l++) + { + rc = vp8_default_zig_zag1d[l]; + + if (bd->qcoeff[rc]) + eob = l; + } + + bd->eob = eob + 1; + } + + rate = cost_coeffs(x, bd, type, a, l); + error = ENCODEMB_INVOKE(&rtcd->encodemb, berr)(b->coeff, bd->dqcoeff) >> 4; + thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100); + + if (thisrd > baserd) + { + bd->qcoeff[k] = cur_qcoef; + bd->dqcoeff[k] = cur_qcoef * dequant_ptr[k]; + } + else + { + baserd = thisrd; + } + + } + + { + int eob = -1; + int rc; + + for (k = 0; k < 16; k++) + { + rc = vp8_default_zig_zag1d[k]; + + if (bd->qcoeff[rc]) + eob = k; + } + + bd->eob = eob + 1; + } + + return; +} + + +void vp8_optimize_mb(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int cost = 0; + int b; + TEMP_CONTEXT t, t2; + int type = 0; + + vp8_setup_temp_context(&t, x->e_mbd.above_context[Y1CONTEXT], x->e_mbd.left_context[Y1CONTEXT], 4); + + if (x->e_mbd.mbmi.mode == SPLITMV || x->e_mbd.mbmi.mode == B_PRED) + type = 3; + + for (b = 0; b < 16; b++) + { + //vp8_optimize_bplus(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + vp8_optimize_b(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd); + } + + vp8_setup_temp_context(&t, x->e_mbd.above_context[UCONTEXT], x->e_mbd.left_context[UCONTEXT], 2); + vp8_setup_temp_context(&t2, x->e_mbd.above_context[VCONTEXT], x->e_mbd.left_context[VCONTEXT], 2); + + for (b = 16; b < 20; b++) + { + //vp8_optimize_bplus(x, b, vp8_block2type[b], t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + vp8_optimize_b(x, b, vp8_block2type[b], t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd); + } + + for (b = 20; b < 24; b++) + { + //vp8_optimize_bplus(x, b, vp8_block2type[b], t2.a + vp8_block2above[b], t2.l + vp8_block2left[b]); + vp8_optimize_b(x, b, vp8_block2type[b], t2.a + vp8_block2above[b], t2.l + vp8_block2left[b], rtcd); + } +} + + + +void vp8_super_slow_yquant_optimization(MACROBLOCK *x, int type, const VP8_ENCODER_RTCD *rtcd) +{ + BLOCK *b = &x->block[0]; + BLOCKD *bd = &x->e_mbd.block[0]; + short *dequant_ptr = &bd->dequant[0][0]; + struct + { + int block; + int pos; + } nzpos[256]; + short saved_qcoefs[256]; + short saved_dqcoefs[256]; + short *coef_ptr = x->coeff; + short *qcoef_ptr = x->e_mbd.qcoeff; + short *dqcoef_ptr = x->e_mbd.dqcoeff; + + int baserate, baseerror, baserd; + int rate, error, thisrd; + int i, k; + int nzcoefcount = 0; + int nc, bestnc = 0; + int besteob; + + //this code has assumption in macroblock coeff buffer layout + for (i = 0; i < 16; i++) + { + // count potential coefficient to be optimized + for (k = !type; k < 16; k++) + { + int qcoef = abs(qcoef_ptr[i*16 + k]); + int coef = abs(coef_ptr[i*16 + k]); + int dq = dequant_ptr[k]; + + if (qcoef && (qcoef * dq > coef) && (qcoef * dq < coef + dq)) + { + nzpos[nzcoefcount].block = i; + nzpos[nzcoefcount].pos = k; + nzcoefcount++; + } + } + } + + // if nothing here, do nothing for this macro_block. + if (!nzcoefcount || nzcoefcount > 15) + { + return; + } + + /****************************************************************************** + looking from each coeffient's perspective, each identifed coefficent above could + have 2 values:roundeddown(x) and roundedup(x). Therefore the total number of + different states is less than 2**nzcoefcount. + ******************************************************************************/ + // save the qunatized coefficents and dequantized coefficicents + vpx_memcpy(saved_qcoefs, x->e_mbd.qcoeff, 256); + vpx_memcpy(saved_dqcoefs, x->e_mbd.dqcoeff, 256); + + baserate = mbycost_coeffs(x); + baseerror = ENCODEMB_INVOKE(&rtcd->encodemb, mberr)(x, !type); + baserd = RDFUNC(x->rdmult, x->rddiv, baserate, baseerror, 100); + + for (nc = 1; nc < (1 << nzcoefcount); nc++) + { + //reset coefficients + vpx_memcpy(x->e_mbd.qcoeff, saved_qcoefs, 256); + vpx_memcpy(x->e_mbd.dqcoeff, saved_dqcoefs, 256); + + for (k = 0; k < nzcoefcount; k++) + { + int bk = nzpos[k].block; + int pos = nzpos[k].pos; + int mbkpos = bk * 16 + pos; + + if ((nc & (1 << k))) + { + int cur_qcoef = x->e_mbd.qcoeff[mbkpos]; + + if (cur_qcoef < 0) + { + x->e_mbd.qcoeff[mbkpos]++; + x->e_mbd.dqcoeff[mbkpos] = x->e_mbd.qcoeff[mbkpos] * dequant_ptr[pos]; + } + else + { + x->e_mbd.qcoeff[mbkpos]--; + x->e_mbd.dqcoeff[mbkpos] = x->e_mbd.qcoeff[mbkpos] * dequant_ptr[pos]; + } + } + } + + for (i = 0; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + { + int eob = -1; + int rc; + int l; + + for (l = 0; l < 16; l++) + { + rc = vp8_default_zig_zag1d[l]; + + if (bd->qcoeff[rc]) + eob = l; + } + + bd->eob = eob + 1; + } + } + + rate = mbycost_coeffs(x); + error = ENCODEMB_INVOKE(&rtcd->encodemb, mberr)(x, !type);; + thisrd = RDFUNC(x->rdmult, x->rddiv, rate, error, 100); + + if (thisrd < baserd) + { + baserd = thisrd; + bestnc = nc; + besteob = bd->eob; + } + } + + //reset coefficients + vpx_memcpy(x->e_mbd.qcoeff, saved_qcoefs, 256); + vpx_memcpy(x->e_mbd.dqcoeff, saved_dqcoefs, 256); + + if (bestnc) + { + for (k = 0; k < nzcoefcount; k++) + { + int bk = nzpos[k].block; + int pos = nzpos[k].pos; + int mbkpos = bk * 16 + pos; + + if ((nc & (1 << k))) + { + int cur_qcoef = x->e_mbd.qcoeff[mbkpos]; + + if (cur_qcoef < 0) + { + x->e_mbd.qcoeff[mbkpos]++; + x->e_mbd.dqcoeff[mbkpos] = x->e_mbd.qcoeff[mbkpos] * dequant_ptr[pos]; + } + else + { + x->e_mbd.qcoeff[mbkpos]--; + x->e_mbd.dqcoeff[mbkpos] = x->e_mbd.qcoeff[mbkpos] * dequant_ptr[pos]; + } + } + } + } + + for (i = 0; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + { + int eob = -1; + int rc; + int l; + + for (l = 0; l < 16; l++) + { + rc = vp8_default_zig_zag1d[l]; + + if (bd->qcoeff[rc]) + eob = l; + } + + bd->eob = eob + 1; + } + } + + return; +} + +static void vp8_find_mb_skip_coef(MACROBLOCK *x) +{ + int i; + + x->e_mbd.mbmi.mb_skip_coeff = 1; + + if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV) + { + for (i = 0; i < 16; i++) + { + x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2); + } + + for (i = 16; i < 25; i++) + { + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } + else + { + for (i = 0; i < 24; i++) + { + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } +} + + +void vp8_optimize_mb_slow(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int cost = 0; + int b; + TEMP_CONTEXT t, t2; + int type = 0; + + + vp8_setup_temp_context(&t, x->e_mbd.above_context[Y1CONTEXT], x->e_mbd.left_context[Y1CONTEXT], 4); + + if (x->e_mbd.mbmi.mode == SPLITMV || x->e_mbd.mbmi.mode == B_PRED) + type = 3; + + vp8_super_slow_yquant_optimization(x, type, rtcd); + /* + for(b=0;b<16;b++) + { + vp8_optimize_b(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + } + */ + + vp8_setup_temp_context(&t, x->e_mbd.above_context[UCONTEXT], x->e_mbd.left_context[UCONTEXT], 2); + + for (b = 16; b < 20; b++) + { + vp8_optimize_b(x, b, vp8_block2type[b], t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd); + } + + vp8_setup_temp_context(&t2, x->e_mbd.above_context[VCONTEXT], x->e_mbd.left_context[VCONTEXT], 2); + + for (b = 20; b < 24; b++) + { + vp8_optimize_b(x, b, vp8_block2type[b], t2.a + vp8_block2above[b], t2.l + vp8_block2left[b], rtcd); + } +} + + +void vp8_optimize_mby(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int cost = 0; + int b; + TEMP_CONTEXT t; + int type = 0; + + if (!x->e_mbd.above_context[Y1CONTEXT]) + return; + + if (!x->e_mbd.left_context[Y1CONTEXT]) + return; + + vp8_setup_temp_context(&t, x->e_mbd.above_context[Y1CONTEXT], x->e_mbd.left_context[Y1CONTEXT], 4); + + if (x->e_mbd.mbmi.mode == SPLITMV || x->e_mbd.mbmi.mode == B_PRED) + type = 3; + + for (b = 0; b < 16; b++) + { + vp8_optimize_b(x, b, type, t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd); + } + +} + +void vp8_optimize_mbuv(MACROBLOCK *x, const VP8_ENCODER_RTCD *rtcd) +{ + int cost = 0; + int b; + TEMP_CONTEXT t, t2; + int type = 0; + + if (!x->e_mbd.above_context[UCONTEXT]) + return; + + if (!x->e_mbd.left_context[UCONTEXT]) + return; + + if (!x->e_mbd.above_context[VCONTEXT]) + return; + + if (!x->e_mbd.left_context[VCONTEXT]) + return; + + + vp8_setup_temp_context(&t, x->e_mbd.above_context[UCONTEXT], x->e_mbd.left_context[UCONTEXT], 2); + vp8_setup_temp_context(&t2, x->e_mbd.above_context[VCONTEXT], x->e_mbd.left_context[VCONTEXT], 2); + + for (b = 16; b < 20; b++) + { + vp8_optimize_b(x, b, vp8_block2type[b], + t.a + vp8_block2above[b], t.l + vp8_block2left[b], rtcd); + + } + + for (b = 20; b < 24; b++) + { + vp8_optimize_b(x, b, vp8_block2type[b], + t2.a + vp8_block2above[b], t2.l + vp8_block2left[b], rtcd); + } + +} +#endif + +void vp8_encode_inter16x16(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_inter_predictors_mb(&x->e_mbd); + + vp8_subtract_mb(rtcd, x); + + vp8_transform_mb(x); + + vp8_quantize_mb(x); + +#if !(CONFIG_REALTIME_ONLY) +#if 1 + + if (x->optimize && x->rddiv > 1) + { + vp8_optimize_mb(x, rtcd); + vp8_find_mb_skip_coef(x); + } + +#endif +#endif + + vp8_inverse_transform_mb(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon16x16mb(IF_RTCD(&rtcd->common->recon), &x->e_mbd); +} + + +/* this funciton is used by first pass only */ +void vp8_encode_inter16x16y(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_inter_predictors_mby(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submby)(x->src_diff, x->src.y_buffer, x->e_mbd.predictor, x->src.y_stride); + + vp8_transform_mby(x); + + vp8_quantize_mby(x); + + vp8_inverse_transform_mby(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon16x16mby(IF_RTCD(&rtcd->common->recon), &x->e_mbd); +} + + +void vp8_encode_inter16x16uv(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_inter_predictors_mbuv(&x->e_mbd); + + ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + + vp8_transform_mbuv(x); + + vp8_quantize_mbuv(x); + + vp8_inverse_transform_mbuv(IF_RTCD(&rtcd->common->idct), &x->e_mbd); + + vp8_recon_intra_mbuv(IF_RTCD(&rtcd->common->recon), &x->e_mbd); +} + + +void vp8_encode_inter16x16uvrd(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x) +{ + vp8_build_inter_predictors_mbuv(&x->e_mbd); + ENCODEMB_INVOKE(&rtcd->encodemb, submbuv)(x->src_diff, x->src.u_buffer, x->src.v_buffer, x->e_mbd.predictor, x->src.uv_stride); + + vp8_transform_mbuvrd(x); + + vp8_quantize_mbuvrd(x); + +}
diff --git a/vp8/encoder/encodemb.h b/vp8/encoder/encodemb.h new file mode 100644 index 0000000..91ca8f5 --- /dev/null +++ b/vp8/encoder/encodemb.h
@@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ENCODEMB_H +#define __INC_ENCODEMB_H + +#include "vpx_ports/config.h" +#include "block.h" + +#define prototype_mberr(sym) \ + int (sym)(MACROBLOCK *mb, int dc) + +#define prototype_berr(sym) \ + int (sym)(short *coeff, short *dqcoeff) + +#define prototype_mbuverr(sym) \ + int (sym)(MACROBLOCK *mb) + +#define prototype_subb(sym) \ + void (sym)(BLOCK *be,BLOCKD *bd, int pitch) + +#define prototype_submby(sym) \ + void (sym)(short *diff, unsigned char *src, unsigned char *pred, int stride) + +#define prototype_submbuv(sym) \ + void (sym)(short *diff, unsigned char *usrc, unsigned char *vsrc,\ + unsigned char *pred, int stride) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/encodemb_x86.h" +#endif + +#if ARCH_ARM +#include "arm/encodemb_arm.h" +#endif + +#ifndef vp8_encodemb_berr +#define vp8_encodemb_berr vp8_block_error_c +#endif +extern prototype_berr(vp8_encodemb_berr); + +#ifndef vp8_encodemb_mberr +#define vp8_encodemb_mberr vp8_mbblock_error_c +#endif +extern prototype_mberr(vp8_encodemb_mberr); + +#ifndef vp8_encodemb_mbuverr +#define vp8_encodemb_mbuverr vp8_mbuverror_c +#endif +extern prototype_mbuverr(vp8_encodemb_mbuverr); + +#ifndef vp8_encodemb_subb +#define vp8_encodemb_subb vp8_subtract_b_c +#endif +extern prototype_subb(vp8_encodemb_subb); + +#ifndef vp8_encodemb_submby +#define vp8_encodemb_submby vp8_subtract_mby_c +#endif +extern prototype_submby(vp8_encodemb_submby); + +#ifndef vp8_encodemb_submbuv +#define vp8_encodemb_submbuv vp8_subtract_mbuv_c +#endif +extern prototype_submbuv(vp8_encodemb_submbuv); + + +typedef struct +{ + prototype_berr(*berr); + prototype_mberr(*mberr); + prototype_mbuverr(*mbuverr); + prototype_subb(*subb); + prototype_submby(*submby); + prototype_submbuv(*submbuv); +} vp8_encodemb_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define ENCODEMB_INVOKE(ctx,fn) (ctx)->fn +#else +#define ENCODEMB_INVOKE(ctx,fn) vp8_encodemb_##fn +#endif + + + +#include "onyx_int.h" +struct VP8_ENCODER_RTCD; +void vp8_encode_inter16x16(const struct VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); + +extern void vp8_stuff_inter16x16(MACROBLOCK *x); + +void vp8_build_dcblock(MACROBLOCK *b); +void vp8_transform_mb(MACROBLOCK *mb); +void vp8_transform_mbuv(MACROBLOCK *x); +void vp8_transform_mbuvrd(MACROBLOCK *x); +void vp8_transform_intra_mby(MACROBLOCK *x); +void vp8_transform_intra_mbyrd(MACROBLOCK *x); +void Encode16x16Y(MACROBLOCK *x); +void Encode16x16UV(MACROBLOCK *x); +void vp8_encode_inter16x16uv(const struct VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); +void vp8_encode_inter16x16uvrd(const struct VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); +void vp8_optimize_mby(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); +void vp8_optimize_mbuv(MACROBLOCK *x, const struct VP8_ENCODER_RTCD *rtcd); +void vp8_encode_inter16x16y(const struct VP8_ENCODER_RTCD *rtcd, MACROBLOCK *x); +#endif
diff --git a/vp8/encoder/encodemv.c b/vp8/encoder/encodemv.c new file mode 100644 index 0000000..f287edc --- /dev/null +++ b/vp8/encoder/encodemv.c
@@ -0,0 +1,445 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "common.h" +#include "encodemv.h" +#include "entropymode.h" +#include "systemdependent.h" + +#include <math.h> + +#ifdef ENTROPY_STATS +extern unsigned int active_section; +#endif + +static void encode_mvcomponent( + vp8_writer *const w, + const int v, + const struct mv_context *mvc +) +{ + const vp8_prob *p = mvc->prob; + const int x = v < 0 ? -v : v; + + if (x < mvnum_short) // Small + { + vp8_write(w, 0, p [mvpis_short]); + vp8_treed_write(w, vp8_small_mvtree, p + MVPshort, x, 3); + + if (!x) + return; // no sign bit + } + else // Large + { + int i = 0; + + vp8_write(w, 1, p [mvpis_short]); + + do + vp8_write(w, (x >> i) & 1, p [MVPbits + i]); + + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + vp8_write(w, (x >> i) & 1, p [MVPbits + i]); + + while (--i > 3); + + if (x & 0xFFF0) + vp8_write(w, (x >> 3) & 1, p [MVPbits + 3]); + } + + vp8_write(w, v < 0, p [MVPsign]); +} +#if 0 +static int max_mv_r = 0; +static int max_mv_c = 0; +#endif +void vp8_encode_motion_vector(vp8_writer *w, const MV *mv, const MV_CONTEXT *mvc) +{ + +#if 0 + { + if (abs(mv->row >> 1) > max_mv_r) + { + FILE *f = fopen("maxmv.stt", "a"); + max_mv_r = abs(mv->row >> 1); + fprintf(f, "New Mv Row Max %6d\n", (mv->row >> 1)); + + if ((abs(mv->row) / 2) != max_mv_r) + fprintf(f, "MV Row conversion error %6d\n", abs(mv->row) / 2); + + fclose(f); + } + + if (abs(mv->col >> 1) > max_mv_c) + { + FILE *f = fopen("maxmv.stt", "a"); + fprintf(f, "New Mv Col Max %6d\n", (mv->col >> 1)); + max_mv_c = abs(mv->col >> 1); + fclose(f); + } + } +#endif + + encode_mvcomponent(w, mv->row >> 1, &mvc[0]); + encode_mvcomponent(w, mv->col >> 1, &mvc[1]); +} + + +static unsigned int cost_mvcomponent(const int v, const struct mv_context *mvc) +{ + const vp8_prob *p = mvc->prob; + const int x = v; //v<0? -v:v; + unsigned int cost; + + if (x < mvnum_short) + { + cost = vp8_cost_zero(p [mvpis_short]) + + vp8_treed_cost(vp8_small_mvtree, p + MVPshort, x, 3); + + if (!x) + return cost; + } + else + { + int i = 0; + cost = vp8_cost_one(p [mvpis_short]); + + do + cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); + + while (++i < 3); + + i = mvlong_width - 1; /* Skip bit 3, which is sometimes implicit */ + + do + cost += vp8_cost_bit(p [MVPbits + i], (x >> i) & 1); + + while (--i > 3); + + if (x & 240) + cost += vp8_cost_bit(p [MVPbits + 3], (x >> 3) & 1); + } + + return cost; // + vp8_cost_bit( p [MVPsign], v < 0); +} +//#define M_LOG2_E 0.693147180559945309417 +//#define log2f(x) (log (x) / (float) M_LOG2_E) + +void vp8_build_component_cost_table(int *mvcost[2], int *mvsadcost[2], const MV_CONTEXT *mvc, int mvc_flag[2]) +{ + int i = 1; //-mv_max; + unsigned int cost0 = 0; + unsigned int cost1 = 0; + + vp8_clear_system_state(); +#if 0 + mvsadcost [0] [0] = 300; + mvsadcost [1] [0] = 300; + + do + { + double z = 256 * (2 * (log2f(2 * i) + .6)); + mvsadcost [0][i] = (int) z; + mvsadcost [1][i] = (int) z; + mvsadcost [0][-i] = (int) z; + mvsadcost [1][-i] = (int) z; + } + while (++i <= mv_max); + +#endif + + i = 1; + + if (mvc_flag[0]) + { + mvcost [0] [0] = cost_mvcomponent(0, &mvc[0]); + + do + { + //mvcost [0] [i] = cost_mvcomponent( i, &mvc[0]); + cost0 = cost_mvcomponent(i, &mvc[0]); + + mvcost [0] [i] = cost0 + vp8_cost_zero(mvc[0].prob[MVPsign]); + mvcost [0] [-i] = cost0 + vp8_cost_one(mvc[0].prob[MVPsign]); + } + while (++i <= mv_max); + } + + i = 1; + + if (mvc_flag[1]) + { + mvcost [1] [0] = cost_mvcomponent(0, &mvc[1]); + + do + { + //mvcost [1] [i] = cost_mvcomponent( i, mvc[1]); + cost1 = cost_mvcomponent(i, &mvc[1]); + + mvcost [1] [i] = cost1 + vp8_cost_zero(mvc[1].prob[MVPsign]); + mvcost [1] [-i] = cost1 + vp8_cost_one(mvc[1].prob[MVPsign]); + } + while (++i <= mv_max); + } + + /* + i=-mv_max; + do + { + mvcost [0] [i] = cost_mvcomponent( i, mvc[0]); + mvcost [1] [i] = cost_mvcomponent( i, mvc[1]); + } + while( ++i <= mv_max); + */ +} + + +// Motion vector probability table update depends on benefit. +// Small correction allows for the fact that an update to an MV probability +// may have benefit in subsequent frames as well as the current one. + +#define MV_PROB_UPDATE_CORRECTION -1 + + +__inline static void calc_prob(vp8_prob *p, const unsigned int ct[2]) +{ + const unsigned int tot = ct[0] + ct[1]; + + if (tot) + { + const vp8_prob x = ((ct[0] * 255) / tot) & -2; + *p = x ? x : 1; + } +} + +static void update( + vp8_writer *const w, + const unsigned int ct[2], + vp8_prob *const cur_p, + const vp8_prob new_p, + const vp8_prob update_p, + int *updated +) +{ + const int cur_b = vp8_cost_branch(ct, *cur_p); + const int new_b = vp8_cost_branch(ct, new_p); + const int cost = 7 + MV_PROB_UPDATE_CORRECTION + ((vp8_cost_one(update_p) - vp8_cost_zero(update_p) + 128) >> 8); + + if (cur_b - new_b > cost) + { + *cur_p = new_p; + vp8_write(w, 1, update_p); + vp8_write_literal(w, new_p >> 1, 7); + *updated = 1; + + } + else + vp8_write(w, 0, update_p); +} + +static void write_component_probs( + vp8_writer *const w, + struct mv_context *cur_mvc, + const struct mv_context *default_mvc_, + const struct mv_context *update_mvc, + const unsigned int events [MVvals], + unsigned int rc, + int *updated +) +{ + vp8_prob *Pcur = cur_mvc->prob; + const vp8_prob *default_mvc = default_mvc_->prob; + const vp8_prob *Pupdate = update_mvc->prob; + unsigned int is_short_ct[2], sign_ct[2]; + + unsigned int bit_ct [mvlong_width] [2]; + + unsigned int short_ct [mvnum_short]; + unsigned int short_bct [mvnum_short-1] [2]; + + vp8_prob Pnew [MVPcount]; + + (void) rc; + vp8_copy_array(Pnew, default_mvc, MVPcount); + + vp8_zero(is_short_ct) + vp8_zero(sign_ct) + vp8_zero(bit_ct) + vp8_zero(short_ct) + vp8_zero(short_bct) + + + //j=0 + { + int j = 0; + + const int c = events [mv_max]; + + is_short_ct [0] += c; // Short vector + short_ct [0] += c; // Magnitude distribution + } + + //j: 1 ~ mv_max (1023) + { + int j = 1; + + do + { + const int c1 = events [mv_max + j]; //positive + const int c2 = events [mv_max - j]; //negative + const int c = c1 + c2; + int a = j; + + sign_ct [0] += c1; + sign_ct [1] += c2; + + if (a < mvnum_short) + { + is_short_ct [0] += c; // Short vector + short_ct [a] += c; // Magnitude distribution + } + else + { + int k = mvlong_width - 1; + is_short_ct [1] += c; // Long vector + + /* bit 3 not always encoded. */ + do + bit_ct [k] [(a >> k) & 1] += c; + + while (--k >= 0); + } + } + while (++j <= mv_max); + } + + /* + { + int j = -mv_max; + do + { + + const int c = events [mv_max + j]; + int a = j; + + if( j < 0) + { + sign_ct [1] += c; + a = -j; + } + else if( j) + sign_ct [0] += c; + + if( a < mvnum_short) + { + is_short_ct [0] += c; // Short vector + short_ct [a] += c; // Magnitude distribution + } + else + { + int k = mvlong_width - 1; + is_short_ct [1] += c; // Long vector + + // bit 3 not always encoded. + + do + bit_ct [k] [(a >> k) & 1] += c; + while( --k >= 0); + } + } while( ++j <= mv_max); + } + */ + + calc_prob(Pnew + mvpis_short, is_short_ct); + + calc_prob(Pnew + MVPsign, sign_ct); + + { + vp8_prob p [mvnum_short - 1]; /* actually only need branch ct */ + int j = 0; + + vp8_tree_probs_from_distribution( + 8, vp8_small_mvencodings, vp8_small_mvtree, + p, short_bct, short_ct, + 256, 1 + ); + + do + calc_prob(Pnew + MVPshort + j, short_bct[j]); + + while (++j < mvnum_short - 1); + } + + { + int j = 0; + + do + calc_prob(Pnew + MVPbits + j, bit_ct[j]); + + while (++j < mvlong_width); + } + + update(w, is_short_ct, Pcur + mvpis_short, Pnew[mvpis_short], *Pupdate++, updated); + + update(w, sign_ct, Pcur + MVPsign, Pnew[MVPsign], *Pupdate++, updated); + + { + const vp8_prob *const new_p = Pnew + MVPshort; + vp8_prob *const cur_p = Pcur + MVPshort; + + int j = 0; + + do + + update(w, short_bct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvnum_short - 1); + } + + { + const vp8_prob *const new_p = Pnew + MVPbits; + vp8_prob *const cur_p = Pcur + MVPbits; + + int j = 0; + + do + + update(w, bit_ct[j], cur_p + j, new_p[j], *Pupdate++, updated); + + while (++j < mvlong_width); + } +} + +void vp8_write_mvprobs(VP8_COMP *cpi) +{ + vp8_writer *const w = & cpi->bc; + MV_CONTEXT *mvc = cpi->common.fc.mvc; + int flags[2] = {0, 0}; +#ifdef ENTROPY_STATS + active_section = 4; +#endif + write_component_probs( + w, &mvc[0], &vp8_default_mv_context[0], &vp8_mv_update_probs[0], cpi->MVcount[0], 0, &flags[0] + ); + write_component_probs( + w, &mvc[1], &vp8_default_mv_context[1], &vp8_mv_update_probs[1], cpi->MVcount[1], 1, &flags[1] + ); + + if (flags[0] || flags[1]) + vp8_build_component_cost_table(cpi->mb.mvcost, cpi->mb.mvsadcost, (const MV_CONTEXT *) cpi->common.fc.mvc, flags); + +#ifdef ENTROPY_STATS + active_section = 5; +#endif +}
diff --git a/vp8/encoder/encodemv.h b/vp8/encoder/encodemv.h new file mode 100644 index 0000000..1c1f450 --- /dev/null +++ b/vp8/encoder/encodemv.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_ENCODEMV_H +#define __INC_ENCODEMV_H + +#include "onyx_int.h" + +void vp8_write_mvprobs(VP8_COMP *); +void vp8_encode_motion_vector(vp8_writer *, const MV *, const MV_CONTEXT *); +void vp8_build_component_cost_table(int *mvcost[2], int *mvsadcost[2], const MV_CONTEXT *mvc, int mvc_flag[2]); + +#endif
diff --git a/vp8/encoder/ethreading.c b/vp8/encoder/ethreading.c new file mode 100644 index 0000000..a0b50d2 --- /dev/null +++ b/vp8/encoder/ethreading.c
@@ -0,0 +1,510 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyx_int.h" +#include "threading.h" +#include "common.h" +#include "extend.h" + + +extern int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset); +extern int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t); +extern void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x); +extern void vp8_build_block_offsets(MACROBLOCK *x); +extern void vp8_setup_block_ptrs(MACROBLOCK *x); + +static +THREAD_FUNCTION thread_encoding_proc(void *p_data) +{ +#if CONFIG_MULTITHREAD + int ithread = ((ENCODETHREAD_DATA *)p_data)->ithread; + VP8_COMP *cpi = (VP8_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr1); + MB_ROW_COMP *mbri = (MB_ROW_COMP *)(((ENCODETHREAD_DATA *)p_data)->ptr2); + ENTROPY_CONTEXT mb_row_left_context[4][4]; + + //printf("Started thread %d\n", ithread); + + while (1) + { + if (cpi->b_multi_threaded == 0) + break; + + //if(WaitForSingleObject(cpi->h_event_mbrencoding[ithread], INFINITE) == WAIT_OBJECT_0) + if (sem_wait(&cpi->h_event_mbrencoding[ithread]) == 0) + { + if (cpi->b_multi_threaded == FALSE) // we're shutting down + break; + else + { + VP8_COMMON *cm = &cpi->common; + int mb_row = mbri->mb_row; + MACROBLOCK *x = &mbri->mb; + MACROBLOCKD *xd = &x->e_mbd; + TOKENEXTRA **tp = &mbri->tp; + int *segment_counts = mbri->segment_counts; + int *totalrate = &mbri->totalrate; + + { + int i; + int recon_yoffset, recon_uvoffset; + int mb_col; + int recon_y_stride = cm->last_frame.y_stride; + int recon_uv_stride = cm->last_frame.uv_stride; + volatile int *last_row_current_mb_col; + + if (ithread > 0) + last_row_current_mb_col = &cpi->mb_row_ei[ithread-1].current_mb_col; + else + last_row_current_mb_col = &cpi->current_mb_col_main; + + // reset above block coeffs + xd->above_context[Y1CONTEXT] = cm->above_context[Y1CONTEXT]; + xd->above_context[UCONTEXT ] = cm->above_context[UCONTEXT ]; + xd->above_context[VCONTEXT ] = cm->above_context[VCONTEXT ]; + xd->above_context[Y2CONTEXT] = cm->above_context[Y2CONTEXT]; + xd->left_context = mb_row_left_context; + + vp8_zero(mb_row_left_context); + + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + + cpi->tplist[mb_row].start = *tp; + + //printf("Thread mb_row = %d\n", mb_row); + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int seg_map_index = (mb_row * cm->mb_cols); + + while (mb_col > (*last_row_current_mb_col - 1) && *last_row_current_mb_col != cm->mb_cols - 1) + { + x86_pause_hint(); + thread_sleep(0); + } + + // Distance of Mb to the various image edges. + // These specified to 8th pel as they are always compared to values that are in 1/8th pel units + xd->mb_to_left_edge = -((mb_col * 16) << 3); + xd->mb_to_right_edge = ((cm->mb_cols - 1 - mb_col) * 16) << 3; + xd->mb_to_top_edge = -((mb_row * 16) << 3); + xd->mb_to_bottom_edge = ((cm->mb_rows - 1 - mb_row) * 16) << 3; + + // Set up limit values for motion vectors used to prevent them extending outside the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); + + xd->dst.y_buffer = cm->new_frame.y_buffer + recon_yoffset; + xd->dst.u_buffer = cm->new_frame.u_buffer + recon_uvoffset; + xd->dst.v_buffer = cm->new_frame.v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + // Is segmentation enabled + // MB level adjutment to quantizer + if (xd->segmentation_enabled) + { + // Code to set segment id in xd->mbmi.segment_id for current MB (with range checking) + if (cpi->segmentation_map[seg_map_index+mb_col] <= 3) + xd->mbmi.segment_id = cpi->segmentation_map[seg_map_index+mb_col]; + else + xd->mbmi.segment_id = 0; + + vp8cx_mb_init_quantizer(cpi, x); + } + else + xd->mbmi.segment_id = 0; // Set to Segment 0 by default + + + if (cm->frame_type == KEY_FRAME) + { + *totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp); +#ifdef MODE_STATS + y_modes[xd->mbmi.mode] ++; +#endif + } + else + { + *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset); + +#ifdef MODE_STATS + inter_y_modes[xd->mbmi.mode] ++; + + if (xd->mbmi.mode == SPLITMV) + { + int b; + + for (b = 0; b < xd->mbmi.partition_count; b++) + { + inter_b_modes[xd->mbmi.partition_bmi[b].mode] ++; + } + } + +#endif + + // Count of last ref frame 0,0 useage + if ((xd->mbmi.mode == ZEROMV) && (xd->mbmi.ref_frame == LAST_FRAME)) + cpi->inter_zz_count ++; + + } + + cpi->tplist[mb_row].stop = *tp; + + xd->gf_active_ptr++; // Increment pointer into gf useage flags structure for next mb + + // store macroblock mode info into context array + vpx_memcpy(&xd->mode_info_context->mbmi, &xd->mbmi, sizeof(xd->mbmi)); + + for (i = 0; i < 16; i++) + vpx_memcpy(&xd->mode_info_context->bmi[i], &xd->block[i].bmi, sizeof(xd->block[i].bmi)); + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + + // Keep track of segment useage + segment_counts[xd->mbmi.segment_id] ++; + + // skip to next mb + xd->mode_info_context++; + + xd->above_context[Y1CONTEXT] += 4; + xd->above_context[UCONTEXT ] += 2; + xd->above_context[VCONTEXT ] += 2; + xd->above_context[Y2CONTEXT] ++; + + cpi->mb_row_ei[ithread].current_mb_col = mb_col; + + } + + //extend the recon for intra prediction + vp8_extend_mb_row( + &cm->new_frame, + xd->dst.y_buffer + 16, + xd->dst.u_buffer + 8, + xd->dst.v_buffer + 8); + + // this is to account for the border + xd->mode_info_context++; + + x->src.y_buffer += 16 * x->src.y_stride * (cpi->encoding_thread_count + 1) - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride * (cpi->encoding_thread_count + 1) - 8 * cm->mb_cols; + + xd->mode_info_context += xd->mode_info_stride * cpi->encoding_thread_count; + + if (ithread == (cpi->encoding_thread_count - 1) || mb_row == cm->mb_rows - 1) + { + //SetEvent(cpi->h_event_main); + sem_post(&cpi->h_event_main); + } + + } + + } + } + } + +#else + (void) p_data; +#endif + + //printf("exit thread %d\n", ithread); + return 0; +} + +static void setup_mbby_copy(MACROBLOCK *mbdst, MACROBLOCK *mbsrc) +{ + + MACROBLOCK *x = mbsrc; + MACROBLOCK *z = mbdst; + int i; + + z->ss = x->ss; + z->ss_count = x->ss_count; + z->searches_per_step = x->searches_per_step; + z->errorperbit = x->errorperbit; + + z->sadperbit16 = x->sadperbit16; + z->sadperbit4 = x->sadperbit4; + z->errthresh = x->errthresh; + z->rddiv = x->rddiv; + z->rdmult = x->rdmult; + + /* + z->mv_col_min = x->mv_col_min; + z->mv_col_max = x->mv_col_max; + z->mv_row_min = x->mv_row_min; + z->mv_row_max = x->mv_row_max; + z->vector_range = x->vector_range ; + */ + + z->vp8_short_fdct4x4 = x->vp8_short_fdct4x4; + z->vp8_short_fdct8x4 = x->vp8_short_fdct8x4; + z->short_fdct4x4rd = x->short_fdct4x4rd; + z->short_fdct8x4rd = x->short_fdct8x4rd; + z->short_fdct8x4rd = x->short_fdct8x4rd; + z->vp8_short_fdct4x4_ptr = x->vp8_short_fdct4x4_ptr; + z->short_walsh4x4 = x->short_walsh4x4; + z->quantize_b = x->quantize_b; + z->quantize_brd = x->quantize_brd; + + /* + z->mvc = x->mvc; + z->src.y_buffer = x->src.y_buffer; + z->src.u_buffer = x->src.u_buffer; + z->src.v_buffer = x->src.v_buffer; + */ + + + vpx_memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); + z->mvcost[0] = &z->mvcosts[0][mv_max+1]; + z->mvcost[1] = &z->mvcosts[1][mv_max+1]; + z->mvsadcost[0] = &z->mvsadcosts[0][mv_max+1]; + z->mvsadcost[1] = &z->mvsadcosts[1][mv_max+1]; + + + vpx_memcpy(z->token_costs, x->token_costs, sizeof(x->token_costs)); + vpx_memcpy(z->inter_bmode_costs, x->inter_bmode_costs, sizeof(x->inter_bmode_costs)); + //memcpy(z->mvcosts, x->mvcosts, sizeof(x->mvcosts)); + //memcpy(z->mvcost, x->mvcost, sizeof(x->mvcost)); + vpx_memcpy(z->mbmode_cost, x->mbmode_cost, sizeof(x->mbmode_cost)); + vpx_memcpy(z->intra_uv_mode_cost, x->intra_uv_mode_cost, sizeof(x->intra_uv_mode_cost)); + vpx_memcpy(z->bmode_costs, x->bmode_costs, sizeof(x->bmode_costs)); + + for (i = 0; i < 25; i++) + { + z->block[i].quant = x->block[i].quant; + z->block[i].zbin = x->block[i].zbin; + z->block[i].zrun_zbin_boost = x->block[i].zrun_zbin_boost; + z->block[i].round = x->block[i].round; + /* + z->block[i].src = x->block[i].src; + */ + z->block[i].src_stride = x->block[i].src_stride; + z->block[i].force_empty = x->block[i].force_empty; + + } + + { + MACROBLOCKD *xd = &x->e_mbd; + MACROBLOCKD *zd = &z->e_mbd; + + /* + zd->mode_info_context = xd->mode_info_context; + zd->mode_info = xd->mode_info; + + zd->mode_info_stride = xd->mode_info_stride; + zd->frame_type = xd->frame_type; + zd->up_available = xd->up_available ; + zd->left_available = xd->left_available; + zd->left_context = xd->left_context; + zd->last_frame_dc = xd->last_frame_dc; + zd->last_frame_dccons = xd->last_frame_dccons; + zd->gold_frame_dc = xd->gold_frame_dc; + zd->gold_frame_dccons = xd->gold_frame_dccons; + zd->mb_to_left_edge = xd->mb_to_left_edge; + zd->mb_to_right_edge = xd->mb_to_right_edge; + zd->mb_to_top_edge = xd->mb_to_top_edge ; + zd->mb_to_bottom_edge = xd->mb_to_bottom_edge; + zd->gf_active_ptr = xd->gf_active_ptr; + zd->frames_since_golden = xd->frames_since_golden; + zd->frames_till_alt_ref_frame = xd->frames_till_alt_ref_frame; + */ + zd->subpixel_predict = xd->subpixel_predict; + zd->subpixel_predict8x4 = xd->subpixel_predict8x4; + zd->subpixel_predict8x8 = xd->subpixel_predict8x8; + zd->subpixel_predict16x16 = xd->subpixel_predict16x16; + zd->segmentation_enabled = xd->segmentation_enabled; + zd->mb_segement_abs_delta = xd->mb_segement_abs_delta; + vpx_memcpy(zd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); + + /* + memcpy(zd->above_context, xd->above_context, sizeof(xd->above_context)); + memcpy(zd->mb_segment_tree_probs, xd->mb_segment_tree_probs, sizeof(xd->mb_segment_tree_probs)); + memcpy(zd->segment_feature_data, xd->segment_feature_data, sizeof(xd->segment_feature_data)); + */ + for (i = 0; i < 25; i++) + { + zd->block[i].dequant = xd->block[i].dequant; + } + } +} + + +void vp8cx_init_mbrthread_data(VP8_COMP *cpi, + MACROBLOCK *x, + MB_ROW_COMP *mbr_ei, + int mb_row, + int count + ) +{ + + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + int i; + (void) mb_row; + + for (i = 0; i < count; i++) + { + MACROBLOCK *mb = & mbr_ei[i].mb; + MACROBLOCKD *mbd = &mb->e_mbd; + + mbd->subpixel_predict = xd->subpixel_predict; + mbd->subpixel_predict8x4 = xd->subpixel_predict8x4; + mbd->subpixel_predict8x8 = xd->subpixel_predict8x8; + mbd->subpixel_predict16x16 = xd->subpixel_predict16x16; +#if CONFIG_RUNTIME_CPU_DETECT + mbd->rtcd = xd->rtcd; +#endif + mbd->gf_active_ptr = xd->gf_active_ptr; + + mb->vector_range = 32; + + vpx_memset(mbr_ei[i].segment_counts, 0, sizeof(mbr_ei[i].segment_counts)); + mbr_ei[i].totalrate = 0; + + mbd->mode_info = cm->mi - 1; + mbd->mode_info_context = cm->mi + x->e_mbd.mode_info_stride * (i + 1); + mbd->mode_info_stride = cm->mode_info_stride; + + mbd->frame_type = cm->frame_type; + + mbd->frames_since_golden = cm->frames_since_golden; + mbd->frames_till_alt_ref_frame = cm->frames_till_alt_ref_frame; + + mb->src = * cpi->Source; + mbd->pre = cm->last_frame; + mbd->dst = cm->new_frame; + + mb->src.y_buffer += 16 * x->src.y_stride * (i + 1); + mb->src.u_buffer += 8 * x->src.uv_stride * (i + 1); + mb->src.v_buffer += 8 * x->src.uv_stride * (i + 1); + + + vp8_build_block_offsets(mb); + + vp8_setup_block_dptrs(mbd); + + vp8_setup_block_ptrs(mb); + + mb->rddiv = cpi->RDDIV; + mb->rdmult = cpi->RDMULT; + + mbd->mbmi.mode = DC_PRED; + mbd->mbmi.uv_mode = DC_PRED; + + mbd->left_context = cm->left_context; + mb->mvc = cm->fc.mvc; + + setup_mbby_copy(&mbr_ei[i].mb, x); + + } +} + + +void vp8cx_create_encoder_threads(VP8_COMP *cpi) +{ + cpi->b_multi_threaded = 0; + + cpi->processor_core_count = 32; //vp8_get_proc_core_count(); + + CHECK_MEM_ERROR(cpi->tplist, vpx_malloc(sizeof(TOKENLIST) * cpi->common.mb_rows)); + +#if CONFIG_MULTITHREAD + + if (cpi->processor_core_count > 1 && cpi->oxcf.multi_threaded > 1) + { + int ithread; + + if (cpi->oxcf.multi_threaded > cpi->processor_core_count) + cpi->encoding_thread_count = cpi->processor_core_count - 1; + else + cpi->encoding_thread_count = cpi->oxcf.multi_threaded - 1; + + + CHECK_MEM_ERROR(cpi->h_encoding_thread, vpx_malloc(sizeof(pthread_t) * cpi->encoding_thread_count)); + CHECK_MEM_ERROR(cpi->h_event_mbrencoding, vpx_malloc(sizeof(sem_t) * cpi->encoding_thread_count)); + CHECK_MEM_ERROR(cpi->mb_row_ei, vpx_memalign(32, sizeof(MB_ROW_COMP) * cpi->encoding_thread_count)); + vpx_memset(cpi->mb_row_ei, 0, sizeof(MB_ROW_COMP) * cpi->encoding_thread_count); + CHECK_MEM_ERROR(cpi->en_thread_data, vpx_malloc(sizeof(ENCODETHREAD_DATA) * cpi->encoding_thread_count)); + //cpi->h_event_main = CreateEvent(NULL, FALSE, FALSE, NULL); + sem_init(&cpi->h_event_main, 0, 0); + + cpi->b_multi_threaded = 1; + + //printf("[VP8:] multi_threaded encoding is enabled with %d threads\n\n", (cpi->encoding_thread_count +1)); + + for (ithread = 0; ithread < cpi->encoding_thread_count; ithread++) + { + //cpi->h_event_mbrencoding[ithread] = CreateEvent(NULL, FALSE, FALSE, NULL); + sem_init(&cpi->h_event_mbrencoding[ithread], 0, 0); + cpi->en_thread_data[ithread].ithread = ithread; + cpi->en_thread_data[ithread].ptr1 = (void *)cpi; + cpi->en_thread_data[ithread].ptr2 = (void *)&cpi->mb_row_ei[ithread]; + + //printf(" call begin thread %d \n", ithread); + + //cpi->h_encoding_thread[ithread] = (HANDLE)_beginthreadex( + // NULL, // security + // 0, // stksize + // thread_encoding_proc, + // (&cpi->en_thread_data[ithread]), // Thread data + // 0, + // NULL); + + pthread_create(&cpi->h_encoding_thread[ithread], 0, thread_encoding_proc, (&cpi->en_thread_data[ithread])); + + } + + } + +#endif +} + +void vp8cx_remove_encoder_threads(VP8_COMP *cpi) +{ +#if CONFIG_MULTITHREAD + + if (cpi->b_multi_threaded) + { + //shutdown other threads + cpi->b_multi_threaded = 0; + { + int i; + + for (i = 0; i < cpi->encoding_thread_count; i++) + { + //SetEvent(cpi->h_event_mbrencoding[i]); + sem_post(&cpi->h_event_mbrencoding[i]); + pthread_join(cpi->h_encoding_thread[i], 0); + } + + for (i = 0; i < cpi->encoding_thread_count; i++) + sem_destroy(&cpi->h_event_mbrencoding[i]); + } + //free thread related resources + vpx_free(cpi->h_event_mbrencoding); + vpx_free(cpi->h_encoding_thread); + vpx_free(cpi->mb_row_ei); + vpx_free(cpi->en_thread_data); + } + +#endif + vpx_free(cpi->tplist); +}
diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c new file mode 100644 index 0000000..c519080 --- /dev/null +++ b/vp8/encoder/firstpass.c
@@ -0,0 +1,2512 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "math.h" +#include "limits.h" +#include "block.h" +#include "onyx_int.h" +#include "variance.h" +#include "encodeintra.h" +#include "setupintrarecon.h" +#include "mcomp.h" +#include "vpx_scale/vpxscale.h" +#include "encodemb.h" +#include "extend.h" +#include "systemdependent.h" +#include "vpx_scale/yv12extend.h" +#include "vpx_mem/vpx_mem.h" +#include "swapyv12buffer.h" +#include <stdio.h> +#include "rdopt.h" +#include "quant_common.h" +#include "encodemv.h" + +//#define OUTPUT_FPF 1 +//#define FIRSTPASS_MM 1 + +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif + +extern void vp8_build_block_offsets(MACROBLOCK *x); +extern void vp8_setup_block_ptrs(MACROBLOCK *x); +extern void vp8cx_frame_init_quantizer(VP8_COMP *cpi); +extern void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, MV *mv); +extern void vp8_alloc_compressor_data(VP8_COMP *cpi); + +//#define GFQ_ADJUSTMENT (40 + ((15*Q)/10)) +//#define GFQ_ADJUSTMENT (80 + ((15*Q)/10)) +#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] +extern int vp8_kf_boost_qadjustment[QINDEX_RANGE]; + +extern const int vp8_gf_boost_qadjustment[QINDEX_RANGE]; + +#define IIFACTOR 1.4 +#define IIKFACTOR1 1.40 +#define IIKFACTOR2 1.5 +#define RMAX 14.0 +#define GF_RMAX 48.0 // 128.0 + +#define DOUBLE_DIVIDE_CHECK(X) ((X)<0?(X)-.000001:(X)+.000001) + +#define POW1 (double)cpi->oxcf.two_pass_vbrbias/100.0 +#define POW2 (double)cpi->oxcf.two_pass_vbrbias/100.0 + +static int vscale_lookup[7] = {0, 1, 1, 2, 2, 3, 3}; +static int hscale_lookup[7] = {0, 0, 1, 1, 2, 2, 3}; + + +void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame); +int vp8_input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps); + +int vp8_encode_intra(VP8_COMP *cpi, MACROBLOCK *x, int use_dc_pred) +{ + + int i; + int intra_pred_var = 0; + (void) cpi; + + if (use_dc_pred) + { + x->e_mbd.mbmi.mode = DC_PRED; + x->e_mbd.mbmi.uv_mode = DC_PRED; + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + + vp8_encode_intra16x16mby(IF_RTCD(&cpi->rtcd), x); + } + else + { + for (i = 0; i < 16; i++) + { + BLOCKD *b = &x->e_mbd.block[i]; + BLOCK *be = &x->block[i]; + + vp8_encode_intra4x4block(IF_RTCD(&cpi->rtcd), x, be, b, B_DC_PRED); + } + } + + intra_pred_var = VARIANCE_INVOKE(&cpi->rtcd.variance, getmbss)(x->src_diff); + + return intra_pred_var; +} + +// Resets the first pass file to the given position using a relative seek from the current position +static void reset_fpf_position(VP8_COMP *cpi, FIRSTPASS_STATS *Position) +{ + cpi->stats_in = Position; +} + +static int lookup_next_frame_stats(VP8_COMP *cpi, FIRSTPASS_STATS *next_frame) +{ + /*FIRSTPASS_STATS * start_pos; + int ret_val; + + start_pos = cpi->stats_in; + ret_val = vp8_input_stats(cpi, next_frame); + reset_fpf_position(cpi, start_pos); + + return ret_val;*/ + + if (cpi->stats_in >= cpi->stats_in_end) + return EOF; + + *next_frame = *cpi->stats_in; + return 1; +} + +// Calculate a modified Error used in distributing bits between easier and harder frames +static double calculate_modified_err(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + double av_err = cpi->total_stats.ssim_weighted_pred_err; + double this_err = this_frame->ssim_weighted_pred_err; + double modified_err; + + //double relative_next_iiratio; + //double next_iiratio; + //double sum_iiratio; + //int i; + + //FIRSTPASS_STATS next_frame; + //FIRSTPASS_STATS *start_pos; + + /*start_pos = cpi->stats_in; + sum_iiratio = 0.0; + i = 0; + while ( (i < 1) && vp8_input_stats(cpi,&next_frame) != EOF ) + { + + next_iiratio = next_frame.intra_error / DOUBLE_DIVIDE_CHECK(next_frame.coded_error); + next_iiratio = ( next_iiratio < 1.0 ) ? 1.0 : (next_iiratio > 20.0) ? 20.0 : next_iiratio; + sum_iiratio += next_iiratio; + i++; + } + if ( i > 0 ) + { + relative_next_iiratio = sum_iiratio / DOUBLE_DIVIDE_CHECK(cpi->avg_iiratio * (double)i); + } + else + { + relative_next_iiratio = 1.0; + } + reset_fpf_position(cpi, start_pos);*/ + + if (this_err > av_err) + modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW1); + else + modified_err = av_err * pow((this_err / DOUBLE_DIVIDE_CHECK(av_err)), POW2); + + /* + relative_next_iiratio = pow(relative_next_iiratio,0.25); + modified_err = modified_err * relative_next_iiratio; + */ + + return modified_err; +} + +double vp8_simple_weight(YV12_BUFFER_CONFIG *source) +{ + int i, j; + int Total = 0; + + unsigned char *src = source->y_buffer; + unsigned char value; + double sum_weights = 0.0; + double Weight; + + // Loop throught the Y plane raw examining levels and creating a weight for the image + for (i = 0; i < source->y_height; i++) + { + for (j = 0; j < source->y_width; j++) + { + value = src[j]; + + if (value >= 64) + Weight = 1.0; + else if (value > 32) + Weight = (value - 32.0f) / 32.0f; + else + Weight = 0.02; + + sum_weights += Weight; + } + + src += source->y_stride; + } + + sum_weights /= (source->y_height * source->y_width); + + return sum_weights; +} + +// This function returns the current per frame maximum bitrate target +int frame_max_bits(VP8_COMP *cpi) +{ + // Max allocation for a single frame based on the max section guidelines passed in and how many bits are left + int max_bits; + + // For CBR we need to also consider buffer fullness. + // If we are running below the optimal level then we need to gradually tighten up on max_bits. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double buffer_fullness_ratio = (double)DOUBLE_DIVIDE_CHECK(cpi->buffer_level) / (double)cpi->oxcf.optimal_buffer_level; + + // For CBR base this on the target average bits per frame plus the maximum sedction rate passed in by the user + max_bits = (int)(cpi->av_per_frame_bandwidth * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); + + // If our buffer is below the optimum level + if (buffer_fullness_ratio < 1.0) + { + // The lower of max_bits / 4 or cpi->av_per_frame_bandwidth / 4. + int min_max_bits = ((cpi->av_per_frame_bandwidth >> 2) < (max_bits >> 2)) ? cpi->av_per_frame_bandwidth >> 2 : max_bits >> 2; + + max_bits = (int)(max_bits * buffer_fullness_ratio); + + if (max_bits < min_max_bits) + max_bits = min_max_bits; // Lowest value we will set ... which should allow the buffer to refil. + } + } + // VBR + else + { + // For VBR base this on the bits and frames left plus the two_pass_vbrmax_section rate passed in by the user + max_bits = (int)(((double)cpi->bits_left / (cpi->total_stats.count - (double)cpi->common.current_video_frame)) * ((double)cpi->oxcf.two_pass_vbrmax_section / 100.0)); + } + + // Trap case where we are out of bits + if (max_bits < 0) + max_bits = 0; + + return max_bits; +} + +void vp8_output_stats(struct vpx_codec_pkt_list *pktlist, + FIRSTPASS_STATS *stats) +{ + struct vpx_codec_cx_pkt pkt; + pkt.kind = VPX_CODEC_STATS_PKT; + pkt.data.twopass_stats.buf = stats; + pkt.data.twopass_stats.sz = sizeof(*stats); + vpx_codec_pkt_list_add(pktlist, &pkt); + +// TEMP debug code +#ifdef OUTPUT_FPF + { + FILE *fpfile; + fpfile = fopen("firstpass.stt", "a"); + + fprintf(fpfile, "%12.0f %12.0f %12.0f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f %12.0f\n", + stats->frame, + stats->intra_error, + stats->coded_error, + stats->ssim_weighted_pred_err, + stats->pcnt_inter, + stats->pcnt_motion, + stats->pcnt_second_ref, + stats->MVr, + stats->mvr_abs, + stats->MVc, + stats->mvc_abs, + stats->MVrv, + stats->MVcv, + stats->mv_in_out_count, + stats->count); + fclose(fpfile); + } +#endif +} + +int vp8_input_stats(VP8_COMP *cpi, FIRSTPASS_STATS *fps) +{ + if (cpi->stats_in >= cpi->stats_in_end) + return EOF; + + *fps = *cpi->stats_in++; + return 1; +} + +void vp8_zero_stats(FIRSTPASS_STATS *section) +{ + section->frame = 0.0; + section->intra_error = 0.0; + section->coded_error = 0.0; + section->ssim_weighted_pred_err = 0.0; + section->pcnt_inter = 0.0; + section->pcnt_motion = 0.0; + section->pcnt_second_ref = 0.0; + section->MVr = 0.0; + section->mvr_abs = 0.0; + section->MVc = 0.0; + section->mvc_abs = 0.0; + section->MVrv = 0.0; + section->MVcv = 0.0; + section->mv_in_out_count = 0.0; + section->count = 0.0; + section->duration = 1.0; +} +void vp8_accumulate_stats(FIRSTPASS_STATS *section, FIRSTPASS_STATS *frame) +{ + section->frame += frame->frame; + section->intra_error += frame->intra_error; + section->coded_error += frame->coded_error; + section->ssim_weighted_pred_err += frame->ssim_weighted_pred_err; + section->pcnt_inter += frame->pcnt_inter; + section->pcnt_motion += frame->pcnt_motion; + section->pcnt_second_ref += frame->pcnt_second_ref; + section->MVr += frame->MVr; + section->mvr_abs += frame->mvr_abs; + section->MVc += frame->MVc; + section->mvc_abs += frame->mvc_abs; + section->MVrv += frame->MVrv; + section->MVcv += frame->MVcv; + section->mv_in_out_count += frame->mv_in_out_count; + section->count += frame->count; + section->duration += frame->duration; +} +void vp8_avg_stats(FIRSTPASS_STATS *section) +{ + if (section->count < 1.0) + return; + + section->intra_error /= section->count; + section->coded_error /= section->count; + section->ssim_weighted_pred_err /= section->count; + section->pcnt_inter /= section->count; + section->pcnt_second_ref /= section->count; + section->pcnt_motion /= section->count; + section->MVr /= section->count; + section->mvr_abs /= section->count; + section->MVc /= section->count; + section->mvc_abs /= section->count; + section->MVrv /= section->count; + section->MVcv /= section->count; + section->mv_in_out_count /= section->count; + section->duration /= section->count; +} + +int vp8_fpmm_get_pos(VP8_COMP *cpi) +{ + return ftell(cpi->fp_motion_mapfile); +} +void vp8_fpmm_reset_pos(VP8_COMP *cpi, int target_pos) +{ + int Offset; + + if (cpi->fp_motion_mapfile) + { + Offset = ftell(cpi->fp_motion_mapfile) - target_pos; + fseek(cpi->fp_motion_mapfile, (int) - Offset, SEEK_CUR); + } +} + +void vp8_advance_fpmm(VP8_COMP *cpi, int count) +{ +#ifdef FIRSTPASS_MM + fseek(cpi->fp_motion_mapfile, (int)(count * cpi->common.MBs), SEEK_CUR); +#endif +} + +void vp8_input_fpmm(VP8_COMP *cpi, int count) +{ +#ifdef FIRSTPASS_MM + + unsigned char *tmp_motion_map; + int i, j; + + if (!cpi->fp_motion_mapfile) + return; // Error + + // Create the first pass motion map structure and set to 0 + CHECK_MEM_ERROR(tmp_motion_map, vpx_calloc(cpi->common.MBs, 1)); + + // Reset the state of the global map + vpx_memset(cpi->fp_motion_map, 0, cpi->common.MBs); + + // Read the specified number of frame maps and set the global map to the highest value seen for each mb. + for (i = 0; i < count; i++) + { + if (fread(tmp_motion_map, 1, cpi->common.MBs, cpi->fp_motion_mapfile) == cpi->common.MBs) + { + for (j = 0; j < cpi->common.MBs; j++) + { + if (tmp_motion_map[j] > 1) + cpi->fp_motion_map[j] += 5; // Intra is flagged + else + cpi->fp_motion_map[j] += tmp_motion_map[j]; + } + } + else + break; // Read error + + } + + if (tmp_motion_map != 0) + vpx_free(tmp_motion_map); + +#endif + +} + +void vp8_init_first_pass(VP8_COMP *cpi) +{ + vp8_zero_stats(&cpi->total_stats); + +#ifdef FIRSTPASS_MM + cpi->fp_motion_mapfile = fopen("fpmotionmap.stt", "wb"); +#endif + +// TEMP debug code +#ifdef OUTPUT_FPF + { + FILE *fpfile; + fpfile = fopen("firstpass.stt", "w"); + fclose(fpfile); + } +#endif + +} + +void vp8_end_first_pass(VP8_COMP *cpi) +{ + vp8_output_stats(cpi->output_pkt_list, &cpi->total_stats); + +#ifdef FIRSTPASS_MM + + if (cpi->fp_motion_mapfile) + fclose(cpi->fp_motion_mapfile); + +#endif + +} +void vp8_zz_motion_search( VP8_COMP *cpi, MACROBLOCK * x, YV12_BUFFER_CONFIG * recon_buffer, int * best_motion_err, int recon_yoffset ) +{ + MACROBLOCKD * const xd = & x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + + unsigned char *src_ptr = (*(b->base_src) + b->src); + int src_stride = b->src_stride; + unsigned char *ref_ptr; + int ref_stride=d->pre_stride; + + // Set up pointers for this macro block recon buffer + xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; + + ref_ptr = (unsigned char *)(*(d->base_pre) + d->pre ); + + VARIANCE_INVOKE(IF_RTCD(&cpi->rtcd.variance), mse16x16) ( src_ptr, src_stride, ref_ptr, ref_stride, (unsigned int *)(best_motion_err)); +} + + +void vp8_first_pass_motion_search(VP8_COMP *cpi, MACROBLOCK *x, MV *ref_mv, MV *best_mv, YV12_BUFFER_CONFIG *recon_buffer, int *best_motion_err, int recon_yoffset ) +{ + MACROBLOCKD *const xd = & x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + int num00; + + MV tmp_mv = {0, 0}; + + int tmp_err; + int step_param = 3; //3; // Dont search over full range for first pass + int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; //3; + int n; + vp8_variance_fn_ptr_t v_fn_ptr; + int new_mv_mode_penalty = 256; + + v_fn_ptr.vf = VARIANCE_INVOKE(IF_RTCD(&cpi->rtcd.variance), mse16x16); + v_fn_ptr.sdf = cpi->fn_ptr.sdf; + v_fn_ptr.sdx4df = cpi->fn_ptr.sdx4df; + + // Set up pointers for this macro block recon buffer + xd->pre.y_buffer = recon_buffer->y_buffer + recon_yoffset; + + // Initial step/diamond search centred on best mv + tmp_err = cpi->diamond_search_sad(x, b, d, ref_mv, &tmp_mv, step_param, x->errorperbit, &num00, &v_fn_ptr, x->mvsadcost, x->mvcost); + if ( tmp_err < INT_MAX-new_mv_mode_penalty ) + tmp_err += new_mv_mode_penalty; + + if (tmp_err < *best_motion_err) + { + *best_motion_err = tmp_err; + best_mv->row = tmp_mv.row; + best_mv->col = tmp_mv.col; + } + + // Further step/diamond searches as necessary + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + tmp_err = cpi->diamond_search_sad(x, b, d, ref_mv, &tmp_mv, step_param + n, x->errorperbit, &num00, &v_fn_ptr, x->mvsadcost, x->mvcost); + if ( tmp_err < INT_MAX-new_mv_mode_penalty ) + tmp_err += new_mv_mode_penalty; + + if (tmp_err < *best_motion_err) + { + *best_motion_err = tmp_err; + best_mv->row = tmp_mv.row; + best_mv->col = tmp_mv.col; + } + } + } +} + +void vp8_first_pass(VP8_COMP *cpi) +{ + int mb_row, mb_col; + MACROBLOCK *const x = & cpi->mb; + VP8_COMMON *const cm = & cpi->common; + MACROBLOCKD *const xd = & x->e_mbd; + + int col_blocks = 4 * cm->mb_cols; + int recon_yoffset, recon_uvoffset; + int recon_y_stride = cm->last_frame.y_stride; + int recon_uv_stride = cm->last_frame.uv_stride; + int intra_error = 0; + int coded_error = 0; + + int sum_mvr = 0, sum_mvc = 0; + int sum_mvr_abs = 0, sum_mvc_abs = 0; + int sum_mvrs = 0, sum_mvcs = 0; + int mvcount = 0; + int intercount = 0; + int second_ref_count = 0; + int intrapenalty = 256; + + int sum_in_vectors = 0; + + MV best_ref_mv = {0, 0}; + MV zero_ref_mv = {0, 0}; + + unsigned char *fp_motion_map_ptr = cpi->fp_motion_map; + + vp8_clear_system_state(); //__asm emms; + + x->src = * cpi->Source; + xd->pre = cm->last_frame; + xd->dst = cm->new_frame; + + vp8_build_block_offsets(x); + + vp8_setup_block_dptrs(&x->e_mbd); + + vp8_setup_block_ptrs(x); + + // set up frame new frame for intra coded blocks + vp8_setup_intra_recon(&cm->new_frame); + vp8cx_frame_init_quantizer(cpi); + + // Initialise the MV cost table to the defaults + //if( cm->current_video_frame == 0) + //if ( 0 ) + { + int flag[2] = {1, 1}; + vp8_initialize_rd_consts(cpi, vp8_dc_quant(cm->base_qindex, cm->y1dc_delta_q)); + vpx_memcpy(cm->fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + vp8_build_component_cost_table(cpi->mb.mvcost, cpi->mb.mvsadcost, (const MV_CONTEXT *) cm->fc.mvc, flag); + } + + // for each macroblock row in image + for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) + { + MV best_ref_mv = {0, 0}; + + // reset above block coeffs + xd->up_available = (mb_row != 0); + recon_yoffset = (mb_row * recon_y_stride * 16); + recon_uvoffset = (mb_row * recon_uv_stride * 8); + + // for each macroblock col in image + for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) + { + int this_error; + int gf_motion_error = INT_MAX; + int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); + + xd->dst.y_buffer = cm->new_frame.y_buffer + recon_yoffset; + xd->dst.u_buffer = cm->new_frame.u_buffer + recon_uvoffset; + xd->dst.v_buffer = cm->new_frame.v_buffer + recon_uvoffset; + xd->left_available = (mb_col != 0); + + // do intra 16x16 prediction + this_error = vp8_encode_intra(cpi, x, use_dc_pred); + + // "intrapenalty" below deals with situations where the intra and inter error scores are very low (eg a plain black frame) + // We do not have special cases in first pass for 0,0 and nearest etc so all inter modes carry an overhead cost estimate fot the mv. + // When the error score is very low this causes us to pick all or lots of INTRA modes and throw lots of key frames. + // This penalty adds a cost matching that of a 0,0 mv to the intra case. + this_error += intrapenalty; + + // Cumulative intra error total + intra_error += this_error; + + // Indicate default assumption of intra in the motion map + *fp_motion_map_ptr = 2; + + // Set up limit values for motion vectors to prevent them extending outside the UMV borders + x->mv_col_min = -((mb_col * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_col_max = ((cm->mb_cols - 1 - mb_col) * 16) + (VP8BORDERINPIXELS - 16); + x->mv_row_min = -((mb_row * 16) + (VP8BORDERINPIXELS - 16)); + x->mv_row_max = ((cm->mb_rows - 1 - mb_row) * 16) + (VP8BORDERINPIXELS - 16); + + // Other than for the first frame do a motion search + if (cm->current_video_frame > 0) + { + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MV tmp_mv = {0, 0}; + int tmp_err; + int motion_error = INT_MAX; + + // Simple 0,0 motion with no mv overhead + vp8_zz_motion_search( cpi, x, &cm->last_frame, &motion_error, recon_yoffset ); + d->bmi.mv.as_mv.row = 0; + d->bmi.mv.as_mv.col = 0; + + // Test last reference frame using the previous best mv as the starting point (best reference) for the search + vp8_first_pass_motion_search(cpi, x, &best_ref_mv, &d->bmi.mv.as_mv, &cm->last_frame, &motion_error, recon_yoffset); + + // If the current best reference mv is not centred on 0,0 then do a 0,0 based search as well + if ((best_ref_mv.col != 0) || (best_ref_mv.row != 0)) + { + tmp_err = INT_MAX; + vp8_first_pass_motion_search(cpi, x, &zero_ref_mv, &tmp_mv, &cm->last_frame, &motion_error, recon_yoffset); + + if ( tmp_err < motion_error ) + { + motion_error = tmp_err; + d->bmi.mv.as_mv.row = tmp_mv.row; + d->bmi.mv.as_mv.col = tmp_mv.col; + } + + } + + // Experimental search in a second reference frame ((0,0) based only) + if (cm->current_video_frame > 1) + { + vp8_first_pass_motion_search(cpi, x, &zero_ref_mv, &tmp_mv, &cm->golden_frame, &gf_motion_error, recon_yoffset); + + if ((gf_motion_error < motion_error) && (gf_motion_error < this_error)) + { + second_ref_count++; + //motion_error = gf_motion_error; + //d->bmi.mv.as_mv.row = tmp_mv.row; + //d->bmi.mv.as_mv.col = tmp_mv.col; + } + /*else + { + xd->pre.y_buffer = cm->last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cm->last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cm->last_frame.v_buffer + recon_uvoffset; + }*/ + + + // Reset to last frame as reference buffer + xd->pre.y_buffer = cm->last_frame.y_buffer + recon_yoffset; + xd->pre.u_buffer = cm->last_frame.u_buffer + recon_uvoffset; + xd->pre.v_buffer = cm->last_frame.v_buffer + recon_uvoffset; + } + + if (motion_error <= this_error) + { + d->bmi.mv.as_mv.row <<= 3; + d->bmi.mv.as_mv.col <<= 3; + this_error = motion_error; + vp8_set_mbmode_and_mvs(x, NEWMV, &d->bmi.mv.as_mv); + vp8_encode_inter16x16y(IF_RTCD(&cpi->rtcd), x); + sum_mvr += d->bmi.mv.as_mv.row; + sum_mvr_abs += abs(d->bmi.mv.as_mv.row); + sum_mvc += d->bmi.mv.as_mv.col; + sum_mvc_abs += abs(d->bmi.mv.as_mv.col); + sum_mvrs += d->bmi.mv.as_mv.row * d->bmi.mv.as_mv.row; + sum_mvcs += d->bmi.mv.as_mv.col * d->bmi.mv.as_mv.col; + intercount++; + + best_ref_mv.row = d->bmi.mv.as_mv.row; + best_ref_mv.col = d->bmi.mv.as_mv.col; + //best_ref_mv.row = 0; + //best_ref_mv.col = 0; + + // Was the vector non-zero + if (d->bmi.mv.as_mv.row || d->bmi.mv.as_mv.col) + { + mvcount++; + + *fp_motion_map_ptr = 1; + + // Does the Row vector point inwards or outwards + if (mb_row < cm->mb_rows / 2) + { + if (d->bmi.mv.as_mv.row > 0) + sum_in_vectors--; + else if (d->bmi.mv.as_mv.row < 0) + sum_in_vectors++; + } + else if (mb_row > cm->mb_rows / 2) + { + if (d->bmi.mv.as_mv.row > 0) + sum_in_vectors++; + else if (d->bmi.mv.as_mv.row < 0) + sum_in_vectors--; + } + + // Does the Row vector point inwards or outwards + if (mb_col < cm->mb_cols / 2) + { + if (d->bmi.mv.as_mv.col > 0) + sum_in_vectors--; + else if (d->bmi.mv.as_mv.col < 0) + sum_in_vectors++; + } + else if (mb_col > cm->mb_cols / 2) + { + if (d->bmi.mv.as_mv.col > 0) + sum_in_vectors++; + else if (d->bmi.mv.as_mv.col < 0) + sum_in_vectors--; + } + } + else + *fp_motion_map_ptr = 0; // 0,0 mv was best + } + else + { + best_ref_mv.row = 0; + best_ref_mv.col = 0; + } + } + + coded_error += this_error; + + // adjust to the next column of macroblocks + x->src.y_buffer += 16; + x->src.u_buffer += 8; + x->src.v_buffer += 8; + + recon_yoffset += 16; + recon_uvoffset += 8; + + // Update the motion map + fp_motion_map_ptr++; + } + + // adjust to the next row of mbs + x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols; + x->src.u_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + x->src.v_buffer += 8 * x->src.uv_stride - 8 * cm->mb_cols; + + //extend the recon for intra prediction + vp8_extend_mb_row(&cm->new_frame, xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8); + vp8_clear_system_state(); //__asm emms; + } + + vp8_clear_system_state(); //__asm emms; + { + double weight = 0.0; + double weigth2 = 0.0; + + FIRSTPASS_STATS fps; + + fps.frame = cm->current_video_frame ; + fps.intra_error = intra_error >> 8; + fps.coded_error = coded_error >> 8; + weight = vp8_simple_weight(cpi->Source); + + if (weight < 0.1) + weight = 0.1; + + fps.ssim_weighted_pred_err = fps.coded_error * weight; + + fps.pcnt_inter = 0.0; + fps.pcnt_motion = 0.0; + fps.MVr = 0.0; + fps.mvr_abs = 0.0; + fps.MVc = 0.0; + fps.mvc_abs = 0.0; + fps.MVrv = 0.0; + fps.MVcv = 0.0; + fps.mv_in_out_count = 0.0; + fps.count = 1.0; + + fps.pcnt_inter = 1.0 * (double)intercount / cm->MBs; + fps.pcnt_second_ref = 1.0 * (double)second_ref_count / cm->MBs; + + if (mvcount > 0) + { + fps.MVr = (double)sum_mvr / (double)mvcount; + fps.mvr_abs = (double)sum_mvr_abs / (double)mvcount; + fps.MVc = (double)sum_mvc / (double)mvcount; + fps.mvc_abs = (double)sum_mvc_abs / (double)mvcount; + fps.MVrv = ((double)sum_mvrs - (fps.MVr * fps.MVr / (double)mvcount)) / (double)mvcount; + fps.MVcv = ((double)sum_mvcs - (fps.MVc * fps.MVc / (double)mvcount)) / (double)mvcount; + fps.mv_in_out_count = (double)sum_in_vectors / (double)(mvcount * 2); + + fps.pcnt_motion = 1.0 * (double)mvcount / cpi->common.MBs; + } + + // TODO: handle the case when duration is set to 0, or something less + // than the full time between subsequent cpi->source_time_stamp s . + fps.duration = cpi->source_end_time_stamp - cpi->source_time_stamp; + + // don't want to do outputstats with a stack variable! + cpi->this_frame_stats = fps; + vp8_output_stats(cpi->output_pkt_list, &cpi->this_frame_stats); + vp8_accumulate_stats(&cpi->total_stats, &fps); + +#ifdef FIRSTPASS_MM + fwrite(cpi->fp_motion_map, 1, cpi->common.MBs, cpi->fp_motion_mapfile); +#endif + } + + // Copy the previous Last Frame into the GF buffer if specific conditions for doing so are met + if ((cm->current_video_frame > 0) && + (cpi->this_frame_stats.pcnt_inter > 0.20) && + ((cpi->this_frame_stats.intra_error / cpi->this_frame_stats.coded_error) > 2.0)) + { + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); + } + + // swap frame pointers so last frame refers to the frame we just compressed + vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); + vp8_yv12_extend_frame_borders(&cm->last_frame); + + // Special case for the first frame. Copy into the GF buffer as a second reference. + if (cm->current_video_frame == 0) + { + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); + } + + + // use this to see what the first pass reconstruction looks like + if (0) + { + char filename[512]; + FILE *recon_file; + sprintf(filename, "enc%04d.yuv", (int) cm->current_video_frame); + + if (cm->current_video_frame == 0) + recon_file = fopen(filename, "wb"); + else + recon_file = fopen(filename, "ab"); + + fwrite(cm->last_frame.buffer_alloc, cm->last_frame.frame_size, 1, recon_file); + fclose(recon_file); + } + + cm->current_video_frame++; + +} +extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; + +#define BASE_ERRPERMB 150 +static int estimate_max_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) +{ + int Q; + int num_mbs = ((Height * Width) / (16 * 16)); + int target_norm_bits_per_mb; + + double err_per_mb = section_err / num_mbs; + double correction_factor; + double corr_high; + double speed_correction = 1.0; + double rolling_ratio; + + double pow_highq = 0.90; + double pow_lowq = 0.40; + + if (section_target_bandwitdh <= 0) + return MAXQ; + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + + // Calculate a corrective factor based on a rolling ratio of bits spent vs target bits + if ((cpi->rolling_target_bits > 0.0) && (cpi->active_worst_quality < cpi->worst_quality)) + { + //double adjustment_rate = 0.985 + (0.00005 * cpi->active_worst_quality); + double adjustment_rate = 0.99; + + rolling_ratio = (double)cpi->rolling_actual_bits / (double)cpi->rolling_target_bits; + + //if ( cpi->est_max_qcorrection_factor > rolling_ratio ) + if (rolling_ratio < 0.95) + //cpi->est_max_qcorrection_factor *= adjustment_rate; + cpi->est_max_qcorrection_factor -= 0.005; + //else if ( cpi->est_max_qcorrection_factor < rolling_ratio ) + else if (rolling_ratio > 1.05) + cpi->est_max_qcorrection_factor += 0.005; + + //cpi->est_max_qcorrection_factor /= adjustment_rate; + + cpi->est_max_qcorrection_factor = (cpi->est_max_qcorrection_factor < 0.1) ? 0.1 : (cpi->est_max_qcorrection_factor > 10.0) ? 10.0 : cpi->est_max_qcorrection_factor; + } + + // Corrections for higher compression speed settings (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Correction factor used for Q values >= 20 + corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); + corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + + // Try and pick a Q that should be high enough to encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + if (Q < 50) + { + correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); + correction_factor = (correction_factor < 0.05) ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; + } + else + correction_factor = corr_high; + + bits_per_mb_at_this_q = (int)(.5 + correction_factor * speed_correction * cpi->est_max_qcorrection_factor * cpi->section_max_qfactor * (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + //bits_per_mb_at_this_q = (int)(.5 + correction_factor * speed_correction * cpi->est_max_qcorrection_factor * (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + return Q; +} +static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width) +{ + int Q; + int num_mbs = ((Height * Width) / (16 * 16)); + int target_norm_bits_per_mb; + + double err_per_mb = section_err / num_mbs; + double correction_factor; + double corr_high; + double speed_correction = 1.0; + double pow_highq = 0.90; + double pow_lowq = 0.40; + + target_norm_bits_per_mb = (section_target_bandwitdh < (1 << 20)) ? (512 * section_target_bandwitdh) / num_mbs : 512 * (section_target_bandwitdh / num_mbs); + + // Corrections for higher compression speed settings (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Correction factor used for Q values >= 20 + corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); + corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + + // Try and pick a Q that can encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + int bits_per_mb_at_this_q; + + if (Q < 50) + { + correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); + correction_factor = (correction_factor < 0.05) ? 0.05 : (correction_factor > 5.0) ? 5.0 : correction_factor; + } + else + correction_factor = corr_high; + + bits_per_mb_at_this_q = (int)(.5 + correction_factor * speed_correction * cpi->est_max_qcorrection_factor * (double)vp8_bits_per_mb[INTER_FRAME][Q] / 1.0); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + return Q; +} + +// Estimate a worst case Q for a KF group +static int estimate_kf_group_q(VP8_COMP *cpi, double section_err, int section_target_bandwitdh, int Height, int Width, double group_iiratio) +{ + int Q; + int num_mbs = ((Height * Width) / (16 * 16)); + int target_norm_bits_per_mb = (512 * section_target_bandwitdh) / num_mbs; + int bits_per_mb_at_this_q; + + double err_per_mb = section_err / num_mbs; + double err_correction_factor; + double corr_high; + double speed_correction = 1.0; + double current_spend_ratio = 1.0; + + double pow_highq = (POW1 < 0.6) ? POW1 + 0.3 : 0.90; + double pow_lowq = (POW1 < 0.7) ? POW1 + 0.1 : 0.80; + + double iiratio_correction_factor = 1.0; + + double combined_correction_factor; + + // Trap special case where the target is <= 0 + if (target_norm_bits_per_mb <= 0) + return MAXQ * 2; + + // Calculate a corrective factor based on a rolling ratio of bits spent vs target bits + // This is clamped to the range 0.1 to 10.0 + if (cpi->long_rolling_target_bits <= 0) + current_spend_ratio = 10.0; + else + { + current_spend_ratio = (double)cpi->long_rolling_actual_bits / (double)cpi->long_rolling_target_bits; + current_spend_ratio = (current_spend_ratio > 10.0) ? 10.0 : (current_spend_ratio < 0.1) ? 0.1 : current_spend_ratio; + } + + // Calculate a correction factor based on the quality of prediction in the sequence as indicated by intra_inter error score ratio (IIRatio) + // The idea here is to favour subsampling in the hardest sections vs the easyest. + iiratio_correction_factor = 1.0 - ((group_iiratio - 6.0) * 0.1); + + if (iiratio_correction_factor < 0.5) + iiratio_correction_factor = 0.5; + + // Corrections for higher compression speed settings (reduced compression expected) + if ((cpi->compressor_speed == 3) || (cpi->compressor_speed == 1)) + { + if (cpi->oxcf.cpu_used <= 5) + speed_correction = 1.04 + (cpi->oxcf.cpu_used * 0.04); + else + speed_correction = 1.25; + } + + // Combine the various factors calculated above + combined_correction_factor = speed_correction * iiratio_correction_factor * current_spend_ratio; + + // Correction factor used for Q values >= 20 + corr_high = pow(err_per_mb / BASE_ERRPERMB, pow_highq); + corr_high = (corr_high < 0.05) ? 0.05 : (corr_high > 5.0) ? 5.0 : corr_high; + + // Try and pick a Q that should be high enough to encode the content at the given rate. + for (Q = 0; Q < MAXQ; Q++) + { + // Q values < 20 treated as a special case + if (Q < 20) + { + err_correction_factor = pow(err_per_mb / BASE_ERRPERMB, (pow_lowq + Q * 0.01)); + err_correction_factor = (err_correction_factor < 0.05) ? 0.05 : (err_correction_factor > 5.0) ? 5.0 : err_correction_factor; + } + else + err_correction_factor = corr_high; + + bits_per_mb_at_this_q = (int)(.5 + err_correction_factor * combined_correction_factor * (double)vp8_bits_per_mb[INTER_FRAME][Q]); + + if (bits_per_mb_at_this_q <= target_norm_bits_per_mb) + break; + } + + // If we could not hit the target even at Max Q then estimate what Q would have bee required + while ((bits_per_mb_at_this_q > target_norm_bits_per_mb) && (Q < (MAXQ * 2))) + { + + bits_per_mb_at_this_q = (int)(0.96 * bits_per_mb_at_this_q); + Q++; + } + + if (0) + { + FILE *f = fopen("estkf_q.stt", "a"); + fprintf(f, "%8d %8d %8d %8.2f %8.3f %8.2f %8.3f %8.3f %8.3f %8d\n", cpi->common.current_video_frame, bits_per_mb_at_this_q, + target_norm_bits_per_mb, err_per_mb, err_correction_factor, + current_spend_ratio, group_iiratio, iiratio_correction_factor, + (double)cpi->buffer_level / (double)cpi->oxcf.optimal_buffer_level, Q); + fclose(f); + } + + return Q; +} +extern void vp8_new_frame_rate(VP8_COMP *cpi, double framerate); + +void vp8_init_second_pass(VP8_COMP *cpi) +{ + FIRSTPASS_STATS this_frame; + FIRSTPASS_STATS *start_pos; + + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + vp8_zero_stats(&cpi->total_stats); + + if (!cpi->stats_in_end) + return; + + cpi->total_stats = *cpi->stats_in_end; + + cpi->total_error_left = cpi->total_stats.ssim_weighted_pred_err; + cpi->total_intra_error_left = cpi->total_stats.intra_error; + cpi->total_coded_error_left = cpi->total_stats.coded_error; + cpi->start_tot_err_left = cpi->total_error_left; + + //cpi->bits_left = (long long)(cpi->total_stats.count * cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); + //cpi->bits_left -= (long long)(cpi->total_stats.count * two_pass_min_rate / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); + + // each frame can have a different duration, as the frame rate in the source + // isn't guaranteed to be constant. The frame rate prior to the first frame + // encoded in the second pass is a guess. However the sum duration is not. + // Its calculated based on the actual durations of all frames from the first + // pass. + vp8_new_frame_rate(cpi, 10000000.0 * cpi->total_stats.count / cpi->total_stats.duration); + + cpi->output_frame_rate = cpi->oxcf.frame_rate; + cpi->bits_left = (long long)(cpi->total_stats.duration * cpi->oxcf.target_bandwidth / 10000000.0) ; + cpi->bits_left -= (long long)(cpi->total_stats.duration * two_pass_min_rate / 10000000.0); + + vp8_avg_stats(&cpi->total_stats); + + // Scan the first pass file and calculate an average Intra / Inter error score ratio for the sequence + { + double sum_iiratio = 0.0; + double IIRatio; + + start_pos = cpi->stats_in; // Note starting "file" position + + while (vp8_input_stats(cpi, &this_frame) != EOF) + { + IIRatio = this_frame.intra_error / DOUBLE_DIVIDE_CHECK(this_frame.coded_error); + IIRatio = (IIRatio < 1.0) ? 1.0 : (IIRatio > 20.0) ? 20.0 : IIRatio; + sum_iiratio += IIRatio; + } + + cpi->avg_iiratio = sum_iiratio / DOUBLE_DIVIDE_CHECK((double)cpi->total_stats.count); + + // Reset file position + reset_fpf_position(cpi, start_pos); + } + + // Scan the first pass file and calculate a modified total error based upon the bias/power function + // used to allocate bits + { + start_pos = cpi->stats_in; // Note starting "file" position + + cpi->modified_total_error_left = 0.0; + + while (vp8_input_stats(cpi, &this_frame) != EOF) + { + cpi->modified_total_error_left += calculate_modified_err(cpi, &this_frame); + } + + reset_fpf_position(cpi, start_pos); // Reset file position + + } + +#ifdef FIRSTPASS_MM + cpi->fp_motion_mapfile = 0; + cpi->fp_motion_mapfile = fopen("fpmotionmap.stt", "rb"); +#endif + +} + +void vp8_end_second_pass(VP8_COMP *cpi) +{ +#ifdef FIRSTPASS_MM + + if (cpi->fp_motion_mapfile) + fclose(cpi->fp_motion_mapfile); + +#endif +} + +// Analyse and define a gf/arf group . +static void define_gf_group(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + FIRSTPASS_STATS next_frame; + FIRSTPASS_STATS *start_pos; + int i; + int count = 0; + int image_size = cpi->common.last_frame.y_width * cpi->common.last_frame.y_height; + double boost_score = 0.0; + double old_boost_score = 0.0; + double gf_group_err = 0.0; + double gf_first_frame_err = 0.0; + double mod_frame_err = 0.0; + + double mv_accumulator_rabs = 0.0; + double mv_accumulator_cabs = 0.0; + double this_mv_rabs; + double this_mv_cabs; + double mv_ratio_accumulator = 0.0; + double distance_factor = 0.0; + double decay_accumulator = 1.0; + + double boost_factor = IIFACTOR; + double loop_decay_rate = 1.00; // Starting decay rate + + double this_frame_mv_in_out = 0.0; + double mv_in_out_accumulator = 0.0; + double abs_mv_in_out_accumulator = 0.0; + double mod_err_per_mb_accumulator = 0.0; + + int max_bits = frame_max_bits(cpi); // Max for a single frame + +#ifdef FIRSTPASS_MM + int fpmm_pos; +#endif + + cpi->gf_group_bits = 0; + cpi->gf_decay_rate = 0; + + vp8_clear_system_state(); //__asm emms; + +#ifdef FIRSTPASS_MM + fpmm_pos = vp8_fpmm_get_pos(cpi); +#endif + + start_pos = cpi->stats_in; + + // Preload the stats for the next frame. + mod_frame_err = calculate_modified_err(cpi, this_frame); + + // Note the error of the frame at the start of the group (this will be the GF frame error if we code a normal gf + gf_first_frame_err = mod_frame_err; + + // Special treatment if the current frame is a key frame (which is also a gf). + // If it is then its error score (and hence bit allocation) need to be subtracted out + // from the calculation for the GF group + if (cpi->common.frame_type == KEY_FRAME) + gf_group_err -= gf_first_frame_err; + + // Scan forward to try and work out how many frames the next gf group should contain and + // what level of boost is appropriate for the GF or ARF that will be coded with the group + i = 0; + + while (((i < cpi->max_gf_interval) || ((cpi->frames_to_key - i) < MIN_GF_INTERVAL)) && (i < cpi->frames_to_key)) + { + double r; + double motion_factor; + double this_frame_mvr_ratio; + double this_frame_mvc_ratio; + + i++; // Increment the loop counter + + // Accumulate error score of frames in this gf group + mod_frame_err = calculate_modified_err(cpi, this_frame); + + gf_group_err += mod_frame_err; + + mod_err_per_mb_accumulator += mod_frame_err / DOUBLE_DIVIDE_CHECK((double)cpi->common.MBs); + + if (EOF == vp8_input_stats(cpi, &next_frame)) + break; + + // Accumulate motion stats. + motion_factor = next_frame.pcnt_motion; + this_mv_rabs = fabs(next_frame.mvr_abs * motion_factor); + this_mv_cabs = fabs(next_frame.mvc_abs * motion_factor); + + mv_accumulator_rabs += fabs(next_frame.mvr_abs * motion_factor); + mv_accumulator_cabs += fabs(next_frame.mvc_abs * motion_factor); + + //Accumulate Motion In/Out of frame stats + this_frame_mv_in_out = next_frame.mv_in_out_count * next_frame.pcnt_motion; + mv_in_out_accumulator += next_frame.mv_in_out_count * next_frame.pcnt_motion; + abs_mv_in_out_accumulator += fabs(next_frame.mv_in_out_count * next_frame.pcnt_motion); + + // If there is a significant amount of motion + if (motion_factor > 0.05) + { + this_frame_mvr_ratio = fabs(next_frame.mvr_abs) / DOUBLE_DIVIDE_CHECK(fabs(next_frame.MVr)); + this_frame_mvc_ratio = fabs(next_frame.mvc_abs) / DOUBLE_DIVIDE_CHECK(fabs(next_frame.MVc)); + + mv_ratio_accumulator += (this_frame_mvr_ratio < next_frame.mvr_abs) ? (this_frame_mvr_ratio * motion_factor) : next_frame.mvr_abs * motion_factor; + mv_ratio_accumulator += (this_frame_mvc_ratio < next_frame.mvc_abs) ? (this_frame_mvc_ratio * motion_factor) : next_frame.mvc_abs * motion_factor; + } + else + { + mv_ratio_accumulator += 0.0; + this_frame_mvr_ratio = 1.0; + this_frame_mvc_ratio = 1.0; + } + + // Underlying boost factor is based on inter intra error ratio + r = (boost_factor * (next_frame.intra_error / DOUBLE_DIVIDE_CHECK(next_frame.coded_error))); + + // Increase boost for frames where new data coming into frame (eg zoom out) + // Slightly reduce boost if there is a net balance of motion out of the frame (zoom in) + // The range for this_frame_mv_in_out is -1.0 to +1.0 + if (this_frame_mv_in_out > 0.0) + r += r * (this_frame_mv_in_out * 2.0); + else + r += r * (this_frame_mv_in_out / 2.0); // In extreme case boost is halved + + if (r > GF_RMAX) + r = GF_RMAX; + + // Adjust loop decay rate + //if ( next_frame.pcnt_inter < loop_decay_rate ) + loop_decay_rate = next_frame.pcnt_inter; + + // High % motion -> somewhat higher decay rate + if ((1.0 - (next_frame.pcnt_motion / 10.0)) < loop_decay_rate) + loop_decay_rate = (1.0 - (next_frame.pcnt_motion / 10.0)); + + distance_factor = sqrt((this_mv_rabs * this_mv_rabs) + (this_mv_cabs * this_mv_cabs)) / 300.0; + distance_factor = ((distance_factor > 1.0) ? 0.0 : (1.0 - distance_factor)); + + if (distance_factor < loop_decay_rate) + loop_decay_rate = distance_factor; + + // Cumulative effect of decay + decay_accumulator = decay_accumulator * loop_decay_rate; + decay_accumulator = decay_accumulator < 0.1 ? 0.1 : decay_accumulator; + //decay_accumulator = ( loop_decay_rate < decay_accumulator ) ? loop_decay_rate : decay_accumulator; + + boost_score += (decay_accumulator * r); + + // Break out conditions. + if ( /* i>4 || */ + ( + (i > MIN_GF_INTERVAL) && // Dont break out with a very short interval + ((cpi->frames_to_key - i) >= MIN_GF_INTERVAL) && // Dont break out very close to a key frame + ((boost_score > 20.0) || (next_frame.pcnt_inter < 0.75)) && + ((mv_ratio_accumulator > 100.0) || + (abs_mv_in_out_accumulator > 3.0) || + (mv_in_out_accumulator < -2.0) || + ((boost_score - old_boost_score) < 2.0) + ) + ) + ) + { + boost_score = old_boost_score; + break; + } + + vpx_memcpy(this_frame, &next_frame, sizeof(*this_frame)); + + old_boost_score = boost_score; + } + + cpi->gf_decay_rate = (i > 0) ? (int)(100.0 * (1.0 - decay_accumulator)) / i : 0; + + // When using CBR apply additional buffer related upper limits + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double max_boost; + + // For cbr apply buffer related limits + if (cpi->drop_frames_allowed) + { + int df_buffer_level = cpi->oxcf.drop_frames_water_mark * (cpi->oxcf.optimal_buffer_level / 100); + + if (cpi->buffer_level > df_buffer_level) + max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + else + max_boost = 0.0; + } + else if (cpi->buffer_level > 0) + { + max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + } + else + { + max_boost = 0.0; + } + + if (boost_score > max_boost) + boost_score = max_boost; + } + + cpi->gfu_boost = (int)(boost_score * 100.0) >> 4; + + // Should we use the alternate refernce frame + if (cpi->oxcf.play_alternate && + (i >= MIN_GF_INTERVAL) && + (i <= (cpi->frames_to_key - MIN_GF_INTERVAL)) && // dont use ARF very near next kf + (((next_frame.pcnt_inter > 0.75) && + ((mv_in_out_accumulator / (double)i > -0.2) || (mv_in_out_accumulator > -2.0)) && + //(cpi->gfu_boost>150) && + (cpi->gfu_boost > 100) && + //(cpi->gfu_boost>AF_THRESH2) && + //((cpi->gfu_boost/i)>AF_THRESH) && + //(decay_accumulator > 0.5) && + (cpi->gf_decay_rate <= (ARF_DECAY_THRESH + (cpi->gfu_boost / 200))) + ) + ) + ) + { + int Boost; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int tmp_q; + int arf_frame_bits = 0; + int group_bits; + + // Estimate the bits to be allocated to the group as a whole + if ((cpi->kf_group_bits > 0) && (cpi->kf_group_error_left > 0)) + group_bits = (int)((double)cpi->kf_group_bits * (gf_group_err / (double)cpi->kf_group_error_left)); + else + group_bits = 0; + + // Boost for arf frame + Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + Boost += (cpi->baseline_gf_interval * 50); + allocation_chunks = (i * 100) + Boost; + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Calculate the number of bits to be spent on the arf based on the boost number + arf_frame_bits = (int)((double)Boost * (group_bits / (double)allocation_chunks)); + + // Estimate if there are enough bits available to make worthwhile use of an arf. + tmp_q = estimate_q(cpi, mod_frame_err, (int)arf_frame_bits, cpi->common.Height, cpi->common.Width); + + // Only use an arf if it is likely we will be able to code it at a lower Q than the surrounding frames. + if (tmp_q < cpi->worst_quality) + { + cpi->source_alt_ref_pending = TRUE; + + // For alt ref frames the error score for the end frame of the group (the alt ref frame) should not contribute to the group total and hence + // the number of bit allocated to the group. Rather it forms part of the next group (it is the GF at the start of the next group) + gf_group_err -= mod_frame_err; + + // Set the interval till the next gf or arf. For ARFs this is the number of frames to be coded before the future frame that is coded as an ARF. + // The future frame itself is part of the next group + cpi->baseline_gf_interval = i - 1; + +#ifdef FIRSTPASS_MM + // Read through the motion map to load up the entry for the ARF + { + int j; + + // Advance to the region of interest + // Current default 2 frames before to 2 frames after the ARF frame itsef + vp8_fpmm_reset_pos(cpi, cpi->fpmm_pos); + + for (j = 0; j < cpi->baseline_gf_interval - 2; j++) + vp8_advance_fpmm(cpi, 1); + + // Read / create a motion map for the region of interest + vp8_input_fpmm(cpi, 5); + } +#endif + } + else + { + cpi->source_alt_ref_pending = FALSE; + cpi->baseline_gf_interval = i; + } + } + else + { + cpi->source_alt_ref_pending = FALSE; + cpi->baseline_gf_interval = i; + } + + // Conventional GF + if (!cpi->source_alt_ref_pending) + { + // Dont allow conventional gf too near the next kf + if ((cpi->frames_to_key - cpi->baseline_gf_interval) < MIN_GF_INTERVAL) + { + while (cpi->baseline_gf_interval < cpi->frames_to_key) + { + if (EOF == vp8_input_stats(cpi, this_frame)) + break; + + cpi->baseline_gf_interval++; + + if (cpi->baseline_gf_interval < cpi->frames_to_key) + gf_group_err += calculate_modified_err(cpi, this_frame); + } + } + } + + // Now decide how many bits should be allocated to the GF group as a proportion of those remaining in the kf group. + // The final key frame group in the clip is treated as a special case where cpi->kf_group_bits is tied to cpi->bits_left. + // This is also important for short clips where there may only be one key frame. + if (cpi->frames_to_key >= (int)(cpi->total_stats.count - cpi->common.current_video_frame)) + { + cpi->kf_group_bits = (cpi->bits_left > 0) ? cpi->bits_left : 0; + } + + // Calculate the bits to be allocated to the group as a whole + if ((cpi->kf_group_bits > 0) && (cpi->kf_group_error_left > 0)) + cpi->gf_group_bits = (int)((double)cpi->kf_group_bits * (gf_group_err / (double)cpi->kf_group_error_left)); + else + cpi->gf_group_bits = 0; + + cpi->gf_group_bits = (cpi->gf_group_bits < 0) ? 0 : (cpi->gf_group_bits > cpi->kf_group_bits) ? cpi->kf_group_bits : cpi->gf_group_bits; + + // Clip cpi->gf_group_bits based on user supplied data rate variability limit (cpi->oxcf.two_pass_vbrmax_section) + if (cpi->gf_group_bits > max_bits * cpi->baseline_gf_interval) + cpi->gf_group_bits = max_bits * cpi->baseline_gf_interval; + + // Reset the file position + reset_fpf_position(cpi, start_pos); + + // Assign bits to the arf or gf. + { + int Boost; + int frames_in_section; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + + // For ARF frames + if (cpi->source_alt_ref_pending) + { + Boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + //Boost += (cpi->baseline_gf_interval * 25); + Boost += (cpi->baseline_gf_interval * 50); + + // Set max and minimum boost and hence minimum allocation + if (Boost > ((cpi->baseline_gf_interval + 1) * 200)) + Boost = ((cpi->baseline_gf_interval + 1) * 200); + else if (Boost < 125) + Boost = 125; + + frames_in_section = cpi->baseline_gf_interval + 1; + allocation_chunks = (frames_in_section * 100) + Boost; + } + // Else for standard golden frames + else + { + // boost based on inter / intra ratio of subsequent frames + Boost = (cpi->gfu_boost * GFQ_ADJUSTMENT) / 100; + + // Set max and minimum boost and hence minimum allocation + if (Boost > (cpi->baseline_gf_interval * 150)) + Boost = (cpi->baseline_gf_interval * 150); + else if (Boost < 125) + Boost = 125; + + frames_in_section = cpi->baseline_gf_interval; + allocation_chunks = (frames_in_section * 100) + (Boost - 100); + } + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Calculate the number of bits to be spent on the gf or arf based on the boost number + cpi->gf_bits = (int)((double)Boost * (cpi->gf_group_bits / (double)allocation_chunks)); + + // If the frame that is to be boosted is simpler than the average for the gf/arf group then use an alternative calculation + // based on the error score of the frame itself + if (mod_frame_err < gf_group_err / (double)cpi->baseline_gf_interval) + { + double alt_gf_grp_bits; + int alt_gf_bits; + + alt_gf_grp_bits = ((double)cpi->kf_group_bits * (mod_frame_err * (double)cpi->baseline_gf_interval) / (double)cpi->kf_group_error_left) ; + alt_gf_bits = (int)((double)Boost * (alt_gf_grp_bits / (double)allocation_chunks)); + + if (cpi->gf_bits > alt_gf_bits) + { + cpi->gf_bits = alt_gf_bits; + } + } + // Else if it is harder than other frames in the group make sure it at least receives an allocation in keeping with + // its relative error score, otherwise it may be worse off than an "un-boosted" frame + else + { + int alt_gf_bits = (int)((double)cpi->kf_group_bits * (mod_frame_err / (double)cpi->kf_group_error_left)); + + if (alt_gf_bits > cpi->gf_bits) + { + cpi->gf_bits = alt_gf_bits; + } + } + + // Apply an additional limit for CBR + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->gf_bits > (cpi->buffer_level >> 1)) + cpi->gf_bits = cpi->buffer_level >> 1; + } + + // Dont allow a negative value for gf_bits + if (cpi->gf_bits < 0) + cpi->gf_bits = 0; + + // Adjust KF group bits and error remainin + cpi->kf_group_error_left -= gf_group_err; + cpi->kf_group_bits -= cpi->gf_group_bits; + + if (cpi->kf_group_bits < 0) + cpi->kf_group_bits = 0; + + // Note the error score left in the remaining frames of the group. + // For normal GFs we want to remove the error score for the first frame of the group (except in Key frame case where this has already happened) + if (!cpi->source_alt_ref_pending && cpi->common.frame_type != KEY_FRAME) + cpi->gf_group_error_left = gf_group_err - gf_first_frame_err; + else + cpi->gf_group_error_left = gf_group_err; + + cpi->gf_group_bits -= cpi->gf_bits; + + if (cpi->gf_group_bits < 0) + cpi->gf_group_bits = 0; + + // Set aside some bits for a mid gf sequence boost + if ((cpi->gfu_boost > 150) && (cpi->baseline_gf_interval > 5)) + { + int pct_extra = (cpi->gfu_boost - 100) / 50; + pct_extra = (pct_extra > 10) ? 10 : pct_extra; + + cpi->mid_gf_extra_bits = (cpi->gf_group_bits * pct_extra) / 100; + cpi->gf_group_bits -= cpi->mid_gf_extra_bits; + } + else + cpi->mid_gf_extra_bits = 0; + + cpi->gf_bits += cpi->min_frame_bandwidth; // Add in minimum for a frame + } + + if (!cpi->source_alt_ref_pending && (cpi->common.frame_type != KEY_FRAME)) // Normal GF and not a KF + { + cpi->per_frame_bandwidth = cpi->gf_bits; // Per frame bit target for this frame + } + + // Adjustment to estimate_max_q based on a measure of complexity of the section + if (cpi->common.frame_type != KEY_FRAME) + { + FIRSTPASS_STATS sectionstats; + double Ratio; + + vp8_zero_stats(§ionstats); + reset_fpf_position(cpi, start_pos); + + for (i = 0 ; i < cpi->baseline_gf_interval ; i++) + { + vp8_input_stats(cpi, &next_frame); + vp8_accumulate_stats(§ionstats, &next_frame); + } + + vp8_avg_stats(§ionstats); + + if (sectionstats.pcnt_motion < .17) + cpi->section_is_low_motion = 1; + else + cpi->section_is_low_motion = 0; + + if (sectionstats.mvc_abs + sectionstats.mvr_abs > 45) + cpi->section_is_fast_motion = 1; + else + cpi->section_is_fast_motion = 0; + + cpi->section_intra_rating = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + + Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + //if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) + //{ + cpi->section_max_qfactor = 1.0 - ((Ratio - 10.0) * 0.025); + + if (cpi->section_max_qfactor < 0.80) + cpi->section_max_qfactor = 0.80; + + //} + //else + // cpi->section_max_qfactor = 1.0; + + reset_fpf_position(cpi, start_pos); + } + +#ifdef FIRSTPASS_MM + // Reset the First pass motion map file position + vp8_fpmm_reset_pos(cpi, fpmm_pos); +#endif +} + +// Allocate bits to a normal frame that is neither a gf an arf or a key frame. +static void assign_std_frame_bits(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + int target_frame_size; // gf_group_error_left + + double modified_err; + double err_fraction; // What portion of the remaining GF group error is used by this frame + + int max_bits = frame_max_bits(cpi); // Max for a single frame + + // The final few frames have special treatment + if (cpi->frames_till_gf_update_due >= (int)(cpi->total_stats.count - cpi->common.current_video_frame)) + { + cpi->gf_group_bits = (cpi->bits_left > 0) ? cpi->bits_left : 0;; + } + + // Calculate modified prediction error used in bit allocation + modified_err = calculate_modified_err(cpi, this_frame); + + if (cpi->gf_group_error_left > 0) + err_fraction = modified_err / cpi->gf_group_error_left; // What portion of the remaining GF group error is used by this frame + else + err_fraction = 0.0; + + target_frame_size = (int)((double)cpi->gf_group_bits * err_fraction); // How many of those bits available for allocation should we give it? + + // Clip to target size to 0 - max_bits (or cpi->gf_group_bits) at the top end. + if (target_frame_size < 0) + target_frame_size = 0; + else + { + if (target_frame_size > max_bits) + target_frame_size = max_bits; + + if (target_frame_size > cpi->gf_group_bits) + target_frame_size = cpi->gf_group_bits; + } + + cpi->gf_group_error_left -= modified_err; // Adjust error remaining + cpi->gf_group_bits -= target_frame_size; // Adjust bits remaining + + if (cpi->gf_group_bits < 0) + cpi->gf_group_bits = 0; + + target_frame_size += cpi->min_frame_bandwidth; // Add in the minimum number of bits that is set aside for every frame. + + // Special case for the frame that lies half way between two gfs + if (cpi->common.frames_since_golden == cpi->baseline_gf_interval / 2) + target_frame_size += cpi->mid_gf_extra_bits; + + cpi->per_frame_bandwidth = target_frame_size; // Per frame bit target for this frame +} + +void vp8_second_pass(VP8_COMP *cpi) +{ + int tmp_q; + int frames_left = (int)(cpi->total_stats.count - cpi->common.current_video_frame); + + FIRSTPASS_STATS this_frame; + FIRSTPASS_STATS this_frame_copy; + + VP8_COMMON *cm = &cpi->common; + + double this_frame_error; + double this_frame_intra_error; + double this_frame_coded_error; + + FIRSTPASS_STATS *start_pos; + + if (!cpi->stats_in) + { + return ; + } + + vp8_clear_system_state(); + + if (EOF == vp8_input_stats(cpi, &this_frame)) + return; + +#ifdef FIRSTPASS_MM + vpx_memset(cpi->fp_motion_map, 0, cpi->common.MBs); + cpi->fpmm_pos = vp8_fpmm_get_pos(cpi); + vp8_advance_fpmm(cpi, 1); // Read this frame's first pass motion map +#endif + + this_frame_error = this_frame.ssim_weighted_pred_err; + this_frame_intra_error = this_frame.intra_error; + this_frame_coded_error = this_frame.coded_error; + + // Store information regarding level of motion etc for use mode decisions. + cpi->motion_speed = (int)(fabs(this_frame.MVr) + fabs(this_frame.MVc)); + cpi->motion_var = (int)(fabs(this_frame.MVrv) + fabs(this_frame.MVcv)); + cpi->inter_lvl = (int)(this_frame.pcnt_inter * 100); + cpi->intra_lvl = (int)((1.0 - this_frame.pcnt_inter) * 100); + cpi->motion_lvl = (int)(this_frame.pcnt_motion * 100); + + start_pos = cpi->stats_in; + + // keyframe and section processing ! + if (cpi->frames_to_key == 0) + { + // Define next KF group and assign bits to it + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + vp8_find_next_key_frame(cpi, &this_frame_copy); + + // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop + // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. + // This is temporary code till we decide what should really happen in this case. + if (cpi->oxcf.error_resilient_mode) + { + cpi->gf_group_bits = cpi->kf_group_bits; + cpi->gf_group_error_left = cpi->kf_group_error_left; + cpi->baseline_gf_interval = cpi->frames_to_key; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + cpi->source_alt_ref_pending = FALSE; + } + + } + + // Is this a GF / ARF (Note that a KF is always also a GF) + if (cpi->frames_till_gf_update_due == 0) + { + // Define next gf group and assign bits to it + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + define_gf_group(cpi, &this_frame_copy); + + // If we are going to code an altref frame at the end of the group and the current frame is not a key frame.... + // If the previous group used an arf this frame has already benefited from that arf boost and it should not be given extra bits + // If the previous group was NOT coded using arf we may want to apply some boost to this GF as well + if (cpi->source_alt_ref_pending && (cpi->common.frame_type != KEY_FRAME)) + { + // Assign a standard frames worth of bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + + // If appropriate (we are switching into ARF active but it was not previously active) apply a boost for the gf at the start of the group. + //if ( !cpi->source_alt_ref_active && (cpi->gfu_boost > 150) ) + if (FALSE) + { + int extra_bits; + int pct_extra = (cpi->gfu_boost - 100) / 50; + + pct_extra = (pct_extra > 20) ? 20 : pct_extra; + + extra_bits = (cpi->gf_group_bits * pct_extra) / 100; + cpi->gf_group_bits -= extra_bits; + cpi->per_frame_bandwidth += extra_bits; + } + } + } + + // Otherwise this is an ordinary frame + else + { + // Special case: Error error_resilient_mode mode does not make much sense for two pass but with its current meaning but this code is designed to stop + // outlandish behaviour if someone does set it when using two pass. It effectively disables GF groups. + // This is temporary code till we decide what should really happen in this case. + if (cpi->oxcf.error_resilient_mode) + { + cpi->frames_till_gf_update_due = cpi->frames_to_key; + + if (cpi->common.frame_type != KEY_FRAME) + { + // Assign bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + } + } + else + { + // Assign bits from those allocated to the GF group + vpx_memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + assign_std_frame_bits(cpi, &this_frame_copy); + } + } + + // Set nominal per second bandwidth for this frame + cpi->target_bandwidth = cpi->per_frame_bandwidth * cpi->output_frame_rate; + if (cpi->target_bandwidth < 0) + cpi->target_bandwidth = 0; + + if (cpi->common.current_video_frame == 0) + { + // guess at 2nd pass q + cpi->est_max_qcorrection_factor = 1.0; + tmp_q = estimate_max_q(cpi, (cpi->total_coded_error_left / frames_left), (int)(cpi->bits_left / frames_left), cpi->common.Height, cpi->common.Width); + + if (tmp_q < cpi->worst_quality) + { + cpi->active_worst_quality = tmp_q; + cpi->ni_av_qi = tmp_q; + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + cpi->ni_av_qi = cpi->worst_quality; + } + } + else + { + if (frames_left < 1) + frames_left = 1; + + tmp_q = estimate_max_q(cpi, (cpi->total_coded_error_left / frames_left), (int)(cpi->bits_left / frames_left), cpi->common.Height, cpi->common.Width); + + // Move active_worst_quality but in a damped way + if (tmp_q > cpi->active_worst_quality) + cpi->active_worst_quality ++; + else if (tmp_q < cpi->active_worst_quality) + cpi->active_worst_quality --; + + cpi->active_worst_quality = ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4; + + // Clamp to user set limits + if (cpi->active_worst_quality > cpi->worst_quality) + cpi->active_worst_quality = cpi->worst_quality; + else if (cpi->active_worst_quality < cpi->best_quality) + cpi->active_worst_quality = cpi->best_quality; + + } + + cpi->frames_to_key --; + cpi->total_error_left -= this_frame_error; + cpi->total_intra_error_left -= this_frame_intra_error; + cpi->total_coded_error_left -= this_frame_coded_error; +} + + +static BOOL test_candidate_kf(VP8_COMP *cpi, FIRSTPASS_STATS *last_frame, FIRSTPASS_STATS *this_frame, FIRSTPASS_STATS *next_frame) +{ + BOOL is_viable_kf = FALSE; + + // Does the frame satisfy the primary criteria of a key frame + // If so, then examine how well it predicts subsequent frames + if ((this_frame->pcnt_second_ref < 0.10) && + (next_frame->pcnt_second_ref < 0.10) && + ((this_frame->pcnt_inter < 0.05) || + ( + (this_frame->pcnt_inter < .25) && + ((this_frame->intra_error / DOUBLE_DIVIDE_CHECK(this_frame->coded_error)) < 2.5) && + ((fabs(last_frame->coded_error - this_frame->coded_error) / DOUBLE_DIVIDE_CHECK(this_frame->coded_error) > .40) || + (fabs(last_frame->intra_error - this_frame->intra_error) / DOUBLE_DIVIDE_CHECK(this_frame->intra_error) > .40) || + ((next_frame->intra_error / DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) > 3.5) + ) + ) + ) + ) + { + int i; + FIRSTPASS_STATS *start_pos; + + FIRSTPASS_STATS local_next_frame; + + double boost_score = 0.0; + double old_boost_score = 0.0; + double decay_accumulator = 1.0; + double next_iiratio; + + vpx_memcpy(&local_next_frame, next_frame, sizeof(*next_frame)); + + // Note the starting file position so we can reset to it + start_pos = cpi->stats_in; + + // Examine how well the key frame predicts subsequent frames + for (i = 0 ; i < 16; i++) + { + next_iiratio = (IIKFACTOR1 * local_next_frame.intra_error / DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error)) ; + + if (next_iiratio > RMAX) + next_iiratio = RMAX; + + // Cumulative effect of decay in prediction quality + if (local_next_frame.pcnt_inter > 0.85) + decay_accumulator = decay_accumulator * local_next_frame.pcnt_inter; + else + decay_accumulator = decay_accumulator * ((0.85 + local_next_frame.pcnt_inter) / 2.0); + + //decay_accumulator = decay_accumulator * local_next_frame.pcnt_inter; + + // Keep a running total + boost_score += (decay_accumulator * next_iiratio); + + // Test various breakout clauses + if ((local_next_frame.pcnt_inter < 0.05) || + (next_iiratio < 1.5) || + ((local_next_frame.pcnt_inter < 0.20) && (next_iiratio < 3.0)) || + ((boost_score - old_boost_score) < 0.5) || + (local_next_frame.intra_error < 200) + ) + { + break; + } + + old_boost_score = boost_score; + + // Get the next frame details + if (EOF == vp8_input_stats(cpi, &local_next_frame)) + break; + } + + // If there is tolerable prediction for at least the next 3 frames then break out else discard this pottential key frame and move on + if (boost_score > 5.0 && (i > 3)) + is_viable_kf = TRUE; + else + { + // Reset the file position + reset_fpf_position(cpi, start_pos); + + is_viable_kf = FALSE; + } + } + + return is_viable_kf; +} +void vp8_find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) +{ + int i; + FIRSTPASS_STATS last_frame; + FIRSTPASS_STATS first_frame; + FIRSTPASS_STATS next_frame; + FIRSTPASS_STATS *start_position; + + double decay_accumulator = 0; + double boost_score = 0; + double old_boost_score = 0.0; + double loop_decay_rate; + + double kf_mod_err = 0.0; + double kf_group_err = 0.0; + double kf_group_intra_err = 0.0; + double kf_group_coded_err = 0.0; + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + vp8_clear_system_state(); //__asm emms; + start_position = cpi->stats_in; + + cpi->common.frame_type = KEY_FRAME; + + // Clear the alt ref active flag as this can never be active on a key frame + cpi->source_alt_ref_active = FALSE; + + // Kf is always a gf so clear frames till next gf counter + cpi->frames_till_gf_update_due = 0; + + cpi->frames_to_key = 1; + + // Take a copy of the initial frame details + vpx_memcpy(&first_frame, this_frame, sizeof(*this_frame)); + + cpi->kf_group_bits = 0; // Estimate of total bits avaialable to kf group + cpi->kf_group_error_left = 0; // Group modified error score. + + kf_mod_err = calculate_modified_err(cpi, this_frame); + + // find the next keyframe + while (cpi->stats_in < cpi->stats_in_end) + { + // Accumulate kf group error + kf_group_err += calculate_modified_err(cpi, this_frame); + + // These figures keep intra and coded error counts for all frames including key frames in the group. + // The effect of the key frame itself can be subtracted out using the first_frame data collected above + kf_group_intra_err += this_frame->intra_error; + kf_group_coded_err += this_frame->coded_error; + + vpx_memcpy(&last_frame, this_frame, sizeof(*this_frame)); + + // Provided that we are not at the end of the file... + if (EOF != vp8_input_stats(cpi, this_frame)) + { + if (lookup_next_frame_stats(cpi, &next_frame) != EOF) + { + if (test_candidate_kf(cpi, &last_frame, this_frame, &next_frame)) + break; + } + } + + // Step on to the next frame + cpi->frames_to_key ++; + + // If we don't have a real key frame within the next two + // forcekeyframeevery intervals then break out of the loop. + if (cpi->frames_to_key >= 2 *(int)cpi->key_frame_frequency) + break; + + } + + // If there is a max kf interval set by the user we must obey it. + // We already breakout of the loop above at 2x max. + // This code centers the extra kf if the actual natural + // interval is between 1x and 2x + if ( cpi->frames_to_key > (int)cpi->key_frame_frequency ) + { + cpi->frames_to_key /= 2; + + // Estimate corrected kf group error + kf_group_err /= 2.0; + kf_group_intra_err /= 2.0; + kf_group_coded_err /= 2.0; + } + + // Special case for the last frame of the file + if (cpi->stats_in >= cpi->stats_in_end) + { + // Accumulate kf group error + kf_group_err += calculate_modified_err(cpi, this_frame); + + // These figures keep intra and coded error counts for all frames including key frames in the group. + // The effect of the key frame itself can be subtracted out using the first_frame data collected above + kf_group_intra_err += this_frame->intra_error; + kf_group_coded_err += this_frame->coded_error; + } + + // Calculate the number of bits that should be assigned to the kf group. + if ((cpi->bits_left > 0) && ((int)cpi->modified_total_error_left > 0)) + { + int max_bits = frame_max_bits(cpi); // Max for a single normal frame (not key frame) + + // Default allocation based on bits left and relative complexity of the section + cpi->kf_group_bits = (int)(cpi->bits_left * (kf_group_err / cpi->modified_total_error_left)); + + // Clip based on maximum per frame rate defined by the user. + if (cpi->kf_group_bits > max_bits * cpi->frames_to_key) + cpi->kf_group_bits = max_bits * cpi->frames_to_key; + + // Additional special case for CBR if buffer is getting full. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // If the buffer is near or above the optimal and this kf group is not being allocated much + // then increase the allocation a bit. + if (cpi->buffer_level >= cpi->oxcf.optimal_buffer_level) + { + int high_water_mark = (cpi->oxcf.optimal_buffer_level + cpi->oxcf.maximum_buffer_size) >> 1; + int min_group_bits; + + // We are at or above the maximum. + if (cpi->buffer_level >= high_water_mark) + { + min_group_bits = (cpi->av_per_frame_bandwidth * cpi->frames_to_key) + (cpi->buffer_level - high_water_mark); + + if (cpi->kf_group_bits < min_group_bits) + cpi->kf_group_bits = min_group_bits; + } + // We are above optimal but below the maximum + else if (cpi->kf_group_bits < (cpi->av_per_frame_bandwidth * cpi->frames_to_key)) + { + int bits_below_av = (cpi->av_per_frame_bandwidth * cpi->frames_to_key) - cpi->kf_group_bits; + cpi->kf_group_bits += (int)((double)bits_below_av * (double)(cpi->buffer_level - cpi->oxcf.optimal_buffer_level) / + (double)(high_water_mark - cpi->oxcf.optimal_buffer_level)); + } + } + } + } + else + cpi->kf_group_bits = 0; + + // Reset the first pass file position + reset_fpf_position(cpi, start_position); + + // determine how big to make this keyframe based on how well the subsequent frames use inter blocks + decay_accumulator = 1.0; + boost_score = 0.0; + loop_decay_rate = 1.00; // Starting decay rate + + for (i = 0 ; i < cpi->frames_to_key ; i++) + { + double r; + + if (EOF == vp8_input_stats(cpi, &next_frame)) + break; + + r = (IIKFACTOR2 * next_frame.intra_error / DOUBLE_DIVIDE_CHECK(next_frame.coded_error)) ; + + if (r > RMAX) + r = RMAX; + + // Adjust loop decay rate + //if ( next_frame.pcnt_inter < loop_decay_rate ) + loop_decay_rate = next_frame.pcnt_inter; + + if ((1.0 - (next_frame.pcnt_motion / 10.0)) < loop_decay_rate) + loop_decay_rate = (1.0 - (next_frame.pcnt_motion / 10.0)); + + decay_accumulator = decay_accumulator * loop_decay_rate; + + boost_score += (decay_accumulator * r); + + if ((i > MIN_GF_INTERVAL) && + ((boost_score - old_boost_score) < 1.0)) + { + break; + } + + old_boost_score = boost_score; + } + + if (1) + { + FIRSTPASS_STATS sectionstats; + double Ratio; + + vp8_zero_stats(§ionstats); + reset_fpf_position(cpi, start_position); + + for (i = 0 ; i < cpi->frames_to_key ; i++) + { + vp8_input_stats(cpi, &next_frame); + vp8_accumulate_stats(§ionstats, &next_frame); + } + + vp8_avg_stats(§ionstats); + + if (sectionstats.pcnt_motion < .17) + cpi->section_is_low_motion = 1; + else + cpi->section_is_low_motion = 0; + + if (sectionstats.mvc_abs + sectionstats.mvr_abs > 45) + cpi->section_is_fast_motion = 1; + else + cpi->section_is_fast_motion = 0; + + cpi->section_intra_rating = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + + Ratio = sectionstats.intra_error / DOUBLE_DIVIDE_CHECK(sectionstats.coded_error); + // if( (Ratio > 11) ) //&& (sectionstats.pcnt_second_ref < .20) ) + //{ + cpi->section_max_qfactor = 1.0 - ((Ratio - 10.0) * 0.025); + + if (cpi->section_max_qfactor < 0.80) + cpi->section_max_qfactor = 0.80; + + //} + //else + // cpi->section_max_qfactor = 1.0; + } + + // When using CBR apply additional buffer fullness related upper limits + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + double max_boost; + + if (cpi->drop_frames_allowed) + { + int df_buffer_level = cpi->oxcf.drop_frames_water_mark * (cpi->oxcf.optimal_buffer_level / 100); + + if (cpi->buffer_level > df_buffer_level) + max_boost = ((double)((cpi->buffer_level - df_buffer_level) * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + else + max_boost = 0.0; + } + else if (cpi->buffer_level > 0) + { + max_boost = ((double)(cpi->buffer_level * 2 / 3) * 16.0) / DOUBLE_DIVIDE_CHECK((double)cpi->av_per_frame_bandwidth); + } + else + { + max_boost = 0.0; + } + + if (boost_score > max_boost) + boost_score = max_boost; + } + + // Reset the first pass file position + reset_fpf_position(cpi, start_position); + + // Work out how many bits to allocate for the key frame itself + if (1) + { + int kf_boost = boost_score; + int allocation_chunks; + int Counter = cpi->frames_to_key; + int alt_kf_bits; + + // Min boost based on kf interval +#if 0 + + while ((kf_boost < 48) && (Counter > 0)) + { + Counter -= 2; + kf_boost ++; + } + +#endif + + if (kf_boost < 48) + { + kf_boost += ((Counter + 1) >> 1); + + if (kf_boost > 48) kf_boost = 48; + } + + // bigger frame sizes need larger kf boosts, smaller frames smaller boosts... + if ((cpi->common.last_frame.y_width * cpi->common.last_frame.y_height) > (320 * 240)) + kf_boost += 2 * (cpi->common.last_frame.y_width * cpi->common.last_frame.y_height) / (320 * 240); + else if ((cpi->common.last_frame.y_width * cpi->common.last_frame.y_height) < (320 * 240)) + kf_boost -= 4 * (320 * 240) / (cpi->common.last_frame.y_width * cpi->common.last_frame.y_height); + + kf_boost = (int)((double)kf_boost * 100.0) >> 4; // Scale 16 to 100 + + // Adjustment to boost based on recent average q + kf_boost = kf_boost * vp8_kf_boost_qadjustment[cpi->ni_av_qi] / 100; + + if (kf_boost < 250) // Min KF boost + kf_boost = 250; + + // We do three calculations for kf size. + // The first is based on the error score for the whole kf group. + // The second (optionaly) on the key frames own error if this is smaller than the average for the group. + // The final one insures that the frame receives at least the allocation it would have received based on its own error score vs the error score remaining + + allocation_chunks = ((cpi->frames_to_key - 1) * 100) + kf_boost; // cpi->frames_to_key-1 because key frame itself is taken care of by kf_boost + + // Normalize Altboost and allocations chunck down to prevent overflow + while (kf_boost > 1000) + { + kf_boost /= 2; + allocation_chunks /= 2; + } + + cpi->kf_group_bits = (cpi->kf_group_bits < 0) ? 0 : cpi->kf_group_bits; + + // Calculate the number of bits to be spent on the key frame + cpi->kf_bits = (int)((double)kf_boost * ((double)cpi->kf_group_bits / (double)allocation_chunks)); + + // Apply an additional limit for CBR + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->kf_bits > ((3 * cpi->buffer_level) >> 2)) + cpi->kf_bits = (3 * cpi->buffer_level) >> 2; + } + + // If the key frame is actually easier than the average for the kf group (which does sometimes happen... eg a blank intro frame) + // Then use an alternate calculation based on the kf error score which should give a smaller key frame. + if (kf_mod_err < kf_group_err / cpi->frames_to_key) + { + double alt_kf_grp_bits = ((double)cpi->bits_left * (kf_mod_err * (double)cpi->frames_to_key) / cpi->modified_total_error_left) ; + + alt_kf_bits = (int)((double)kf_boost * (alt_kf_grp_bits / (double)allocation_chunks)); + + if (cpi->kf_bits > alt_kf_bits) + { + cpi->kf_bits = alt_kf_bits; + } + } + // Else if it is much harder than other frames in the group make sure it at least receives an allocation in keeping with its relative error score + else + { + alt_kf_bits = (int)((double)cpi->bits_left * (kf_mod_err / cpi->modified_total_error_left)); + + if (alt_kf_bits > cpi->kf_bits) + { + cpi->kf_bits = alt_kf_bits; + } + } + + cpi->kf_group_bits -= cpi->kf_bits; + cpi->kf_bits += cpi->min_frame_bandwidth; // Add in the minimum frame allowance + + cpi->per_frame_bandwidth = cpi->kf_bits; // Peer frame bit target for this frame + cpi->target_bandwidth = cpi->kf_bits * cpi->output_frame_rate; // Convert to a per second bitrate + } + + // Note the total error score of the kf group minus the key frame itself + cpi->kf_group_error_left = (int)(kf_group_err - kf_mod_err); + + // Adjust the count of total modified error left. + // The count of bits left is adjusted elsewhere based on real coded frame sizes + cpi->modified_total_error_left -= kf_group_err; + + if (cpi->oxcf.allow_spatial_resampling) + { + int resample_trigger = FALSE; + int last_kf_resampled = FALSE; + int kf_q; + int scale_val = 0; + int hr, hs, vr, vs; + int new_width = cpi->oxcf.Width; + int new_height = cpi->oxcf.Height; + + int projected_buffer_level = cpi->buffer_level; + int tmp_q; + + double projected_bits_perframe; + double group_iiratio = (kf_group_intra_err - first_frame.intra_error) / (kf_group_coded_err - first_frame.coded_error); + double err_per_frame = kf_group_err / cpi->frames_to_key; + double bits_per_frame; + double av_bits_per_frame; + double effective_size_ratio; + + if ((cpi->common.Width != cpi->oxcf.Width) || (cpi->common.Height != cpi->oxcf.Height)) + last_kf_resampled = TRUE; + + // Set back to unscaled by defaults + cpi->common.horiz_scale = NORMAL; + cpi->common.vert_scale = NORMAL; + + // Calculate Average bits per frame. + //av_bits_per_frame = cpi->bits_left/(double)(cpi->total_stats.count - cpi->common.current_video_frame); + av_bits_per_frame = cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate); + //if ( av_bits_per_frame < 0.0 ) + // av_bits_per_frame = 0.0 + + // CBR... Use the clip average as the target for deciding resample + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + bits_per_frame = av_bits_per_frame; + } + + // In VBR we want to avoid downsampling in easy section unless we are under extreme pressure + // So use the larger of target bitrate for this sectoion or average bitrate for sequence + else + { + bits_per_frame = cpi->kf_group_bits / cpi->frames_to_key; // This accounts for how hard the section is... + + if (bits_per_frame < av_bits_per_frame) // Dont turn to resampling in easy sections just because they have been assigned a small number of bits + bits_per_frame = av_bits_per_frame; + } + + // bits_per_frame should comply with our minimum + if (bits_per_frame < (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100)) + bits_per_frame = (cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + // Work out if spatial resampling is necessary + kf_q = estimate_kf_group_q(cpi, err_per_frame, bits_per_frame, new_height, new_width, group_iiratio); + + // If we project a required Q higher than the maximum allowed Q then make a guess at the actual size of frames in this section + projected_bits_perframe = bits_per_frame; + tmp_q = kf_q; + + while (tmp_q > cpi->worst_quality) + { + projected_bits_perframe *= 1.04; + tmp_q--; + } + + // Guess at buffer level at the end of the section + projected_buffer_level = cpi->buffer_level - (int)((projected_bits_perframe - av_bits_per_frame) * cpi->frames_to_key); + + if (0) + { + FILE *f = fopen("Subsamle.stt", "a"); + fprintf(f, " %8d %8d %8d %8d %12.0f %8d %8d %8d\n", cpi->common.current_video_frame, kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->frames_to_key, cpi->kf_group_bits / cpi->frames_to_key, new_height, new_width); + fclose(f); + } + + // The trigger for spatial resampling depends on the various parameters such as whether we are streaming (CBR) or VBR. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Trigger resample if we are projected to fall below down sample level or + // resampled last time and are projected to remain below the up sample level + if ((projected_buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) || + (last_kf_resampled && (projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)))) + //( ((cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100))) && + // ((projected_buffer_level < (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100))) )) + resample_trigger = TRUE; + else + resample_trigger = FALSE; + } + else + { + long long clip_bits = (long long)(cpi->total_stats.count * cpi->oxcf.target_bandwidth / DOUBLE_DIVIDE_CHECK((double)cpi->oxcf.frame_rate)); + long long over_spend = cpi->oxcf.starting_buffer_level - cpi->buffer_level; + long long over_spend2 = cpi->oxcf.starting_buffer_level - projected_buffer_level; + + if ((last_kf_resampled && (kf_q > cpi->worst_quality)) || // If triggered last time the threshold for triggering again is reduced + ((kf_q > cpi->worst_quality) && // Projected Q higher than allowed and ... + (over_spend > clip_bits / 20))) // ... Overspend > 5% of total bits + resample_trigger = TRUE; + else + resample_trigger = FALSE; + + } + + if (resample_trigger) + { + while ((kf_q >= cpi->worst_quality) && (scale_val < 6)) + { + scale_val ++; + + cpi->common.vert_scale = vscale_lookup[scale_val]; + cpi->common.horiz_scale = hscale_lookup[scale_val]; + + Scale2Ratio(cpi->common.horiz_scale, &hr, &hs); + Scale2Ratio(cpi->common.vert_scale, &vr, &vs); + + new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; + new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; + + // Reducing the area to 1/4 does not reduce the complexity (err_per_frame) to 1/4... + // effective_sizeratio attempts to provide a crude correction for this + effective_size_ratio = (double)(new_width * new_height) / (double)(cpi->oxcf.Width * cpi->oxcf.Height); + effective_size_ratio = (1.0 + (3.0 * effective_size_ratio)) / 4.0; + + // Now try again and see what Q we get with the smaller image size + kf_q = estimate_kf_group_q(cpi, err_per_frame * effective_size_ratio, bits_per_frame, new_height, new_width, group_iiratio); + + if (0) + { + FILE *f = fopen("Subsamle.stt", "a"); + fprintf(f, "******** %8d %8d %8d %12.0f %8d %8d %8d\n", kf_q, cpi->common.horiz_scale, cpi->common.vert_scale, kf_group_err / cpi->frames_to_key, cpi->kf_group_bits / cpi->frames_to_key, new_height, new_width); + fclose(f); + } + } + } + + if ((cpi->common.Width != new_width) || (cpi->common.Height != new_height)) + { + cpi->common.Width = new_width; + cpi->common.Height = new_height; + vp8_alloc_compressor_data(cpi); + } + } +}
diff --git a/vp8/encoder/firstpass.h b/vp8/encoder/firstpass.h new file mode 100644 index 0000000..d7b52f3 --- /dev/null +++ b/vp8/encoder/firstpass.h
@@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if !defined __INC_FIRSTPASS_H +#define __INC_FIRSTPASS_H + +extern void vp8_init_first_pass(VP8_COMP *cpi); +extern void vp8_first_pass(VP8_COMP *cpi); +extern void vp8_end_first_pass(VP8_COMP *cpi); + +extern void vp8_init_second_pass(VP8_COMP *cpi); +extern void vp8_second_pass(VP8_COMP *cpi); +extern void vp8_end_second_pass(VP8_COMP *cpi); + +#endif
diff --git a/vp8/encoder/generic/csystemdependent.c b/vp8/encoder/generic/csystemdependent.c new file mode 100644 index 0000000..52aab66 --- /dev/null +++ b/vp8/encoder/generic/csystemdependent.c
@@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "variance.h" +#include "onyx_int.h" + + +void vp8_arch_x86_encoder_init(VP8_COMP *cpi); + + +void (*vp8_fast_quantize_b)(BLOCK *b, BLOCKD *d); +extern void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d); + +void (*vp8_yv12_copy_partial_frame_ptr)(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); +extern void vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction); + +void vp8_cmachine_specific_config(VP8_COMP *cpi) +{ +#if CONFIG_RUNTIME_CPU_DETECT + cpi->rtcd.common = &cpi->common.rtcd; + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_c; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_c; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_c; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_c; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_c; + + cpi->rtcd.variance.sad16x16x3 = vp8_sad16x16x3_c; + cpi->rtcd.variance.sad16x8x3 = vp8_sad16x8x3_c; + cpi->rtcd.variance.sad8x16x3 = vp8_sad8x16x3_c; + cpi->rtcd.variance.sad8x8x3 = vp8_sad8x8x3_c; + cpi->rtcd.variance.sad4x4x3 = vp8_sad4x4x3_c; + + cpi->rtcd.variance.sad16x16x4d = vp8_sad16x16x4d_c; + cpi->rtcd.variance.sad16x8x4d = vp8_sad16x8x4d_c; + cpi->rtcd.variance.sad8x16x4d = vp8_sad8x16x4d_c; + cpi->rtcd.variance.sad8x8x4d = vp8_sad8x8x4d_c; + cpi->rtcd.variance.sad4x4x4d = vp8_sad4x4x4d_c; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_c; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_c; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_c; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_c; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_c; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_c; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_c; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_c; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_c; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_c; + cpi->rtcd.variance.subpixmse16x16 = vp8_sub_pixel_mse16x16_c; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_c; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_c; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_c; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_c; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_c;; + cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_c; + + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_c; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_c; + cpi->rtcd.fdct.fast4x4 = vp8_fast_fdct4x4_c; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_c; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_c; + + cpi->rtcd.encodemb.berr = vp8_block_error_c; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_c; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_c; + cpi->rtcd.encodemb.subb = vp8_subtract_b_c; + cpi->rtcd.encodemb.submby = vp8_subtract_mby_c; + cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_c; + + cpi->rtcd.quantize.quantb = vp8_regular_quantize_b; + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_c; + + cpi->rtcd.search.full_search = vp8_full_search_sad; + cpi->rtcd.search.diamond_search = vp8_diamond_search_sad; +#endif + + // Pure C: + vp8_yv12_copy_partial_frame_ptr = vp8_yv12_copy_partial_frame; + + +#if ARCH_X86 || ARCH_X86_64 + vp8_arch_x86_encoder_init(cpi); +#endif + +}
diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c new file mode 100644 index 0000000..d80059d --- /dev/null +++ b/vp8/encoder/mcomp.c
@@ -0,0 +1,1467 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "mcomp.h" +#include "vpx_mem/vpx_mem.h" + +#include <stdio.h> +#include <limits.h> +#include <math.h> + +#ifdef ENTROPY_STATS +static int mv_ref_ct [31] [4] [2]; +static int mv_mode_cts [4] [2]; +#endif + +static int mv_bits_sadcost[256]; + +void vp8cx_init_mv_bits_sadcost() +{ + int i; + + for (i = 0; i < 256; i++) + { + mv_bits_sadcost[i] = (int)sqrt(i * 16); + } +} + + +int vp8_mv_bit_cost(MV *mv, MV *ref, int *mvcost[2], int Weight) +{ + // MV costing is based on the distribution of vectors in the previous frame and as such will tend to + // over state the cost of vectors. In addition coding a new vector can have a knock on effect on the + // cost of subsequent vectors and the quality of prediction from NEAR and NEAREST for subsequent blocks. + // The "Weight" parameter allows, to a limited extent, for some account to be taken of these factors. + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col) >> 1]) * Weight) >> 7; +} + +int vp8_mv_err_cost(MV *mv, MV *ref, int *mvcost[2], int error_per_bit) +{ + //int i; + //return ((mvcost[0][(mv->row - ref->row)>>1] + mvcost[1][(mv->col - ref->col)>>1] + 128) * error_per_bit) >> 8; + //return ( (vp8_mv_bit_cost(mv, ref, mvcost, 100) + 128) * error_per_bit) >> 8; + + //i = (vp8_mv_bit_cost(mv, ref, mvcost, 100) * error_per_bit + 128) >> 8; + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col) >> 1]) * error_per_bit + 128) >> 8; + //return (vp8_mv_bit_cost(mv, ref, mvcost, 128) * error_per_bit + 128) >> 8; +} + + +static int mv_bits(MV *mv, MV *ref, int *mvcost[2]) +{ + // get the estimated number of bits for a motion vector, to be used for costing in SAD based + // motion estimation + return ((mvcost[0][(mv->row - ref->row) >> 1] + mvcost[1][(mv->col - ref->col)>> 1]) + 128) >> 8; +} + +void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + + // Generate offsets for 4 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 4; +} + +void vp8_init3smotion_compensation(MACROBLOCK *x, int stride) +{ + int Len; + int search_site_count = 0; + + // Generate offsets for 8 search sites per step. + Len = MAX_FIRST_STEP; + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = 0; + search_site_count++; + + while (Len > 0) + { + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = 0; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = -Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = 0; + x->ss[search_site_count].offset = Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = -Len; + x->ss[search_site_count].offset = -Len * stride + Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = -Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride - Len; + search_site_count++; + + // Compute offsets for search sites. + x->ss[search_site_count].mv.col = Len; + x->ss[search_site_count].mv.row = Len; + x->ss[search_site_count].offset = Len * stride + Len; + search_site_count++; + + + // Contract. + Len /= 2; + } + + x->ss_count = search_site_count; + x->searches_per_step = 8; +} + + +#define MVC(r,c) (((mvcost[0][(r)-rr] + mvcost[1][(c) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (*(d->base_pre) + d->pre + ((r)>>2) * d->pre_stride + ((c)>>2)) // pointer to predictor base of a motionvector +#define SP(x) (((x)&3)<<1) // convert motion vector component to offset for svf calc +#define DIST(r,c) svf( PRE(r,c), d->pre_stride, SP(c),SP(r), z,b->src_stride,&sse) // returns subpixel variance error function. +#define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; +#define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) IFMVCV(r,c,{if((v = ERR(r,c)) < besterr) { besterr = v; br=r; bc=c; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define MAX(x,y) (((x)>(y))?(x):(y)) + +//#define CHECK_BETTER(v,r,c) if((v = ERR(r,c)) < besterr) { besterr = v; br=r; bc=c; } + +int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + + int rr = ref_mv->row >> 1, rc = ref_mv->col >> 1; + int br = bestmv->row << 2, bc = bestmv->col << 2; + int tr = br, tc = bc; + unsigned int besterr = INT_MAX; + unsigned int left, right, up, down, diag; + unsigned int sse; + unsigned int whichdir; + unsigned int halfiters = 4; + unsigned int quarteriters = 4; + + int minc = MAX(x->mv_col_min << 2, (ref_mv->col >> 1) - ((1 << mvlong_width) - 1)); + int maxc = MIN(x->mv_col_max << 2, (ref_mv->col >> 1) + ((1 << mvlong_width) - 1)); + int minr = MAX(x->mv_row_min << 2, (ref_mv->row >> 1) - ((1 << mvlong_width) - 1)); + int maxr = MIN(x->mv_row_max << 2, (ref_mv->row >> 1) + ((1 << mvlong_width) - 1)); + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + + // calculate central point error + besterr = vf(y, d->pre_stride, z, b->src_stride, &sse); + besterr += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + while (--halfiters) + { + // 1/2 pel + CHECK_BETTER(left, tr, tc - 2); + CHECK_BETTER(right, tr, tc + 2); + CHECK_BETTER(up, tr - 2, tc); + CHECK_BETTER(down, tr + 2, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 2, tc - 2); + break; + case 1: + CHECK_BETTER(diag, tr - 2, tc + 2); + break; + case 2: + CHECK_BETTER(diag, tr + 2, tc - 2); + break; + case 3: + CHECK_BETTER(diag, tr + 2, tc + 2); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + // TODO: Each subsequent iteration checks at least one point in common with the last iteration could be 2 ( if diag selected) + // 1/4 pel + while (--quarteriters) + { + CHECK_BETTER(left, tr, tc - 1); + CHECK_BETTER(right, tr, tc + 1); + CHECK_BETTER(up, tr - 1, tc); + CHECK_BETTER(down, tr + 1, tc); + + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + + switch (whichdir) + { + case 0: + CHECK_BETTER(diag, tr - 1, tc - 1); + break; + case 1: + CHECK_BETTER(diag, tr - 1, tc + 1); + break; + case 2: + CHECK_BETTER(diag, tr + 1, tc - 1); + break; + case 3: + CHECK_BETTER(diag, tr + 1, tc + 1); + break; + } + + // no reason to check the same one again. + if (tr == br && tc == bc) + break; + + tr = br; + tc = bc; + } + + bestmv->row = br << 1; + bestmv->col = bc << 1; + + if ((abs(bestmv->col - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs(bestmv->row - ref_mv->row) > MAX_FULL_PEL_VAL)) + return INT_MAX; + + return besterr; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef ERR +#undef CHECK_BETTER +#undef MIN +#undef MAX +int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + int bestmse = INT_MAX; + MV startmv; + //MV this_mv; + MV this_mv; + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + int whichdir ; + + + // Trap uncodable vectors + if ((abs((bestmv->col << 3) - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs((bestmv->row << 3) - ref_mv->row) > MAX_FULL_PEL_VAL)) + { + bestmv->row <<= 3; + bestmv->col <<= 3; + return INT_MAX; + } + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vf(y, d->pre_stride, z, b->src_stride, &sse); + bestmse += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.row = startmv.row; + this_mv.col = ((startmv.col - 8) | 4); + left = svf(y - 1, d->pre_stride, 4, 0, z, b->src_stride, &sse); + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 8; + right = svf(y, d->pre_stride, 4, 0, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + this_mv.row = ((startmv.row - 8) | 4); + up = svf(y - d->pre_stride, d->pre_stride, 0, 4, z, b->src_stride, &sse); + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 8; + down = svf(y, d->pre_stride, 0, 4, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + // whichdir must be 0-4. Therefore, one of the cases below + // must run through. However, because there is no default + // and diag is not set elsewhere, we get a compile warning + diag = 0; + //for(whichdir =0;whichdir<4;whichdir++) + //{ + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - 1 - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 1: + this_mv.col += 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 2: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row += 4; + diag = svf(y - 1, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 3: + this_mv.col += 4; + this_mv.row += 4; + diag = svf(y, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +// } + + + // time to check quarter pels. + if (bestmv->row < startmv.row) + y -= d->pre_stride; + + if (bestmv->col < startmv.col) + y--; + + startmv = *bestmv; + + + + // go left then right and check error + this_mv.row = startmv.row; + + if (startmv.col & 7) + { + this_mv.col = startmv.col - 2; + left = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + left = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse); + } + + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 4; + right = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + + if (startmv.row & 7) + { + this_mv.row = startmv.row - 2; + up = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.row = (startmv.row - 8) | 6; + up = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 4; + down = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + + // now check 1 more diagonal + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + +// for(whichdir=0;whichdir<4;whichdir++) +// { + this_mv = startmv; + + switch (whichdir) + { + case 0: + + if (startmv.row & 7) + { + this_mv.row -= 2; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse);; + } + } + else + { + this_mv.row = (startmv.row - 8) | 6; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - d->pre_stride - 1, d->pre_stride, 6, 6, z, b->src_stride, &sse); + } + } + + break; + case 1: + this_mv.col += 2; + + if (startmv.row & 7) + { + this_mv.row -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.row = (startmv.row - 8) | 6; + diag = svf(y - d->pre_stride, d->pre_stride, this_mv.col & 7, 6, z, b->src_stride, &sse); + } + + break; + case 2: + this_mv.row += 2; + + if (startmv.col & 7) + { + this_mv.col -= 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + } + else + { + this_mv.col = (startmv.col - 8) | 6; + diag = svf(y - 1, d->pre_stride, 6, this_mv.row & 7, z, b->src_stride, &sse);; + } + + break; + case 3: + this_mv.col += 2; + this_mv.row += 2; + diag = svf(y, d->pre_stride, this_mv.col & 7, this_mv.row & 7, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +// } + + return bestmse; +} + +int vp8_find_best_half_pixel_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + int bestmse = INT_MAX; + MV startmv; + //MV this_mv; + MV this_mv; + unsigned char *y = *(d->base_pre) + d->pre + (bestmv->row) * d->pre_stride + bestmv->col; + unsigned char *z = (*(b->base_src) + b->src); + int left, right, up, down, diag; + unsigned int sse; + + // Trap uncodable vectors + if ((abs((bestmv->col << 3) - ref_mv->col) > MAX_FULL_PEL_VAL) || (abs((bestmv->row << 3) - ref_mv->row) > MAX_FULL_PEL_VAL)) + { + bestmv->row <<= 3; + bestmv->col <<= 3; + return INT_MAX; + } + + // central mv + bestmv->row <<= 3; + bestmv->col <<= 3; + startmv = *bestmv; + + // calculate central point error + bestmse = vf(y, d->pre_stride, z, b->src_stride, &sse); + bestmse += vp8_mv_err_cost(bestmv, ref_mv, mvcost, error_per_bit); + + // go left then right and check error + this_mv.row = startmv.row; + this_mv.col = ((startmv.col - 8) | 4); + left = svf(y - 1, d->pre_stride, 4, 0, z, b->src_stride, &sse); + left += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (left < bestmse) + { + *bestmv = this_mv; + bestmse = left; + } + + this_mv.col += 8; + right = svf(y, d->pre_stride, 4, 0, z, b->src_stride, &sse); + right += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (right < bestmse) + { + *bestmv = this_mv; + bestmse = right; + } + + // go up then down and check error + this_mv.col = startmv.col; + this_mv.row = ((startmv.row - 8) | 4); + up = svf(y - d->pre_stride, d->pre_stride, 0, 4, z, b->src_stride, &sse); + up += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (up < bestmse) + { + *bestmv = this_mv; + bestmse = up; + } + + this_mv.row += 8; + down = svf(y, d->pre_stride, 0, 4, z, b->src_stride, &sse); + down += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (down < bestmse) + { + *bestmv = this_mv; + bestmse = down; + } + + // somewhat strangely not doing all the diagonals for half pel is slower than doing them. +#if 0 + // now check 1 more diagonal - + whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); + this_mv = startmv; + + switch (whichdir) + { + case 0: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - 1 - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 1: + this_mv.col += 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 2: + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row += 4; + diag = svf(y - 1, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + case 3: + this_mv.col += 4; + this_mv.row += 4; + diag = svf(y, d->pre_stride, 4, 4, z, b->src_stride, &sse); + break; + } + + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +#else + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = (this_mv.row - 8) | 4; + diag = svf(y - 1 - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col += 8; + diag = svf(y - d->pre_stride, d->pre_stride, 4, 4, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col = (this_mv.col - 8) | 4; + this_mv.row = startmv.row + 4; + diag = svf(y - 1, d->pre_stride, 4, 4, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + + this_mv.col += 8; + diag = svf(y, d->pre_stride, 4, 4, z, b->src_stride, &sse); + diag += vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + + if (diag < bestmse) + { + *bestmv = this_mv; + bestmse = diag; + } + +#endif + return bestmse; +} + + +#define MVC(r,c) (((mvsadcost[0][((r)<<2)-rr] + mvsadcost[1][((c)<<2) - rc]) * error_per_bit + 128 )>>8 ) // estimated cost of a motion vector (r,c) +#define PRE(r,c) (*(d->base_pre) + d->pre + (r) * d->pre_stride + (c)) // pointer to predictor base of a motionvector +#define DIST(r,c,v) sf( src,src_stride,PRE(r,c),d->pre_stride, v) // returns sad error score. +#define ERR(r,c,v) (MVC(r,c)+DIST(r,c,v)) // returns distortion + motion vector cost +#define CHECK_BETTER(v,r,c) if ((v = ERR(r,c,besterr)) < besterr) { besterr = v; br=r; bc=c; } // checks if (r,c) has better score than previous best + +int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_t vf, + vp8_sad_fn_t sf, + int *mvsadcost[2], + int *mvcost[2] +) +{ + MV hex[6] = { { -2, 0}, { -1, -2}, { -1, 2}, {2, 0}, {1, 2}, {1, -2} } ; + MV neighbors[8] = { { -1, -1}, { -1, 0}, { -1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} } ; + int i, j; + unsigned char *src = (*(b->base_src) + b->src); + int src_stride = b->src_stride; + int rr = ref_mv->row, rc = ref_mv->col, br = rr, bc = rc, tr, tc; + unsigned int besterr, thiserr = 0x7fffffff; + + if (rc < x->mv_col_min) bc = x->mv_col_min; + + if (rc > x->mv_col_max) bc = x->mv_col_max; + + if (rr < x->mv_row_min) br = x->mv_row_min; + + if (rr > x->mv_row_max) br = x->mv_row_max; + + rr >>= 1; + rc >>= 1; + br >>= 3; + bc >>= 3; + + besterr = ERR(br, bc, thiserr); + + // hex search jbb changed to 127 to avoid max 256 problem steping by 2. + for (j = 0; j < 127; j++) + { + tr = br; + tc = bc; + + for (i = 0; i < 6; i++) + { + int nr = tr + hex[i].row, nc = tc + hex[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + CHECK_BETTER(thiserr, nr, nc); + } + + if (tr == br && tc == bc) + break; + } + + // check 8 1 away neighbors + tr = br; + tc = bc; + + for (i = 0; i < 8; i++) + { + int nr = tr + neighbors[i].row, nc = tc + neighbors[i].col; + + if (nc < x->mv_col_min) continue; + + if (nc > x->mv_col_max) continue; + + if (nr < x->mv_row_min) continue; + + if (nr > x->mv_row_max) continue; + + CHECK_BETTER(thiserr, nr, nc); + } + + best_mv->row = br; + best_mv->col = bc; + + return vf(src, src_stride, PRE(br, bc), d->pre_stride, &thiserr) + MVC(br, bc) ; +} +#undef MVC +#undef PRE +#undef SP +#undef DIST +#undef ERR +#undef CHECK_BETTER +int vp8_diamond_search_sad +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvsadcost[2], + int *mvcost[2] +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + unsigned char *best_address; + + int tot_steps; + MV this_mv; + + int bestsad = INT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + int thissad; + + // Work out the start point for the search + in_what = (unsigned char *)(*(d->base_pre) + d->pre + (ref_row * (d->pre_stride)) + ref_col); + best_address = in_what; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + best_mv->row = ref_row; + best_mv->col = ref_col; + + *num00 = 0; + + for (step = 0; step < tot_steps ; step++) + { + for (j = 0 ; j < x->searches_per_step ; j++) + { + // Trap illegal vectors + this_row_offset = best_mv->row + ss[i].mv.row; + this_col_offset = best_mv->col + ss[i].mv.col; + + if ((this_col_offset > x->mv_col_min) && (this_col_offset < x->mv_col_max) && + (this_row_offset > x->mv_row_min) && (this_row_offset < x->mv_row_max)) + + { + check_here = ss[i].offset + best_address; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.row = this_row_offset << 3; + this_mv.col = this_col_offset << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + + i++; + } + + if (best_site != last_site) + { + best_mv->row += ss[best_site].mv.row; + best_mv->col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +} + +int vp8_diamond_search_sadx4 +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_ptr_t *fn_ptr, + int *mvsadcost[2], + int *mvcost[2] +) +{ + int i, j, step; + + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + unsigned char *best_address; + + int tot_steps; + MV this_mv; + + unsigned int bestsad = UINT_MAX; + int best_site = 0; + int last_site = 0; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + int this_row_offset; + int this_col_offset; + search_site *ss; + + unsigned char *check_here; + unsigned int thissad; + + // Work out the start point for the search + in_what = (unsigned char *)(*(d->base_pre) + d->pre + (ref_row * (d->pre_stride)) + ref_col); + best_address = in_what; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Check the starting position + bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // search_param determines the length of the initial step and hence the number of iterations + // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = (MAX_FIRST_STEP/4) pel... etc. + ss = &x->ss[search_param * x->searches_per_step]; + tot_steps = (x->ss_count / x->searches_per_step) - search_param; + + i = 1; + best_mv->row = ref_row; + best_mv->col = ref_col; + + *num00 = 0; + + for (step = 0; step < tot_steps ; step++) + { + int check_row_min, check_col_min, check_row_max, check_col_max; + + check_row_min = x->mv_row_min - best_mv->row; + check_row_max = x->mv_row_max - best_mv->row; + check_col_min = x->mv_col_min - best_mv->col; + check_col_max = x->mv_col_max - best_mv->col; + + for (j = 0 ; j < x->searches_per_step ; j += 4) + { + unsigned char *block_offset[4]; + unsigned int valid_block[4]; + int all_in = 1, t; + + for (t = 0; t < 4; t++) + { + valid_block [t] = (ss[t+i].mv.col > check_col_min); + valid_block [t] &= (ss[t+i].mv.col < check_col_max); + valid_block [t] &= (ss[t+i].mv.row > check_row_min); + valid_block [t] &= (ss[t+i].mv.row < check_row_max); + + all_in &= valid_block[t]; + block_offset[t] = ss[i+t].offset + best_address; + } + + if (all_in) + { + unsigned int sad_array[4]; + + fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array); + + for (t = 0; t < 4; t++, i++) + { + thissad = sad_array[t]; + + if (thissad < bestsad) + { + this_mv.row = (best_mv->row + ss[i].mv.row) << 3; + this_mv.col = (best_mv->col + ss[i].mv.col) << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + } + else + { + int t; + + for (t = 0; t < 4; i++, t++) + { + // Trap illegal vectors + if (valid_block[t]) + + { + check_here = block_offset[t]; + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_row_offset = best_mv->row + ss[i].mv.row; + this_col_offset = best_mv->col + ss[i].mv.col; + + this_mv.row = this_row_offset << 3; + this_mv.col = this_col_offset << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_site = i; + } + } + } + } + } + } + + if (best_site != last_site) + { + best_mv->row += ss[best_site].mv.row; + best_mv->col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + last_site = best_site; + } + else if (best_address == in_what) + (*num00)++; + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad == INT_MAX) + return INT_MAX; + + return fn_ptr->vf(what, what_stride, best_address, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); +} + + +#if !(CONFIG_REALTIME_ONLY) +int vp8_full_search_sad(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int error_per_bit, int distance, vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], int *mvsadcost[2]) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + int mv_stride = d->pre_stride; + unsigned char *bestaddress; + MV *best_mv = &d->bmi.mv.as_mv; + MV this_mv; + int bestsad = INT_MAX; + int r, c; + + unsigned char *check_here; + int thissad; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + // Work out the mid point for the search + in_what = *(d->base_pre) + d->pre; + bestaddress = in_what + (ref_row * d->pre_stride) + ref_col; + + best_mv->row = ref_row; + best_mv->col = ref_col; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Baseline value at the centre + + //bestsad = fn_ptr->sf( what,what_stride,bestaddress,in_what_stride) + (int)sqrt(vp8_mv_err_cost(ref_mv,ref_mv, mvcost,error_per_bit*14)); + bestsad = fn_ptr->sdf(what, what_stride, bestaddress, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.row = r << 3; + check_here = r * mv_stride + in_what + col_min; + + for (c = col_min; c < col_max; c++) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + this_mv.col = c << 3; + //thissad += (int)sqrt(vp8_mv_err_cost(&this_mv,ref_mv, mvcost,error_per_bit*14)); + //thissad += error_per_bit * mv_bits_sadcost[mv_bits(&this_mv, ref_mv, mvcost)]; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); //mv_bits(error_per_bit, &this_mv, ref_mv, mvsadcost); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + + check_here++; + } + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + else + return INT_MAX; +} + +int vp8_full_search_sadx3(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *ref_mv, int error_per_bit, int distance, vp8_variance_fn_ptr_t *fn_ptr, int *mvcost[2], int *mvsadcost[2]) +{ + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what; + int in_what_stride = d->pre_stride; + int mv_stride = d->pre_stride; + unsigned char *bestaddress; + MV *best_mv = &d->bmi.mv.as_mv; + MV this_mv; + unsigned int bestsad = UINT_MAX; + int r, c; + + unsigned char *check_here; + unsigned int thissad; + + int ref_row = ref_mv->row >> 3; + int ref_col = ref_mv->col >> 3; + + int row_min = ref_row - distance; + int row_max = ref_row + distance; + int col_min = ref_col - distance; + int col_max = ref_col + distance; + + unsigned int sad_array[3]; + + // Work out the mid point for the search + in_what = *(d->base_pre) + d->pre; + bestaddress = in_what + (ref_row * d->pre_stride) + ref_col; + + best_mv->row = ref_row; + best_mv->col = ref_col; + + // We need to check that the starting point for the search (as indicated by ref_mv) is within the buffer limits + if ((ref_col > x->mv_col_min) && (ref_col < x->mv_col_max) && + (ref_row > x->mv_row_min) && (ref_row < x->mv_row_max)) + { + // Baseline value at the centre + bestsad = fn_ptr->sdf(what, what_stride, bestaddress, in_what_stride, 0x7fffffff) + vp8_mv_err_cost(ref_mv, ref_mv, mvsadcost, error_per_bit); + } + + // Apply further limits to prevent us looking using vectors that stretch beyiond the UMV border + if (col_min < x->mv_col_min) + col_min = x->mv_col_min; + + if (col_max > x->mv_col_max) + col_max = x->mv_col_max; + + if (row_min < x->mv_row_min) + row_min = x->mv_row_min; + + if (row_max > x->mv_row_max) + row_max = x->mv_row_max; + + for (r = row_min; r < row_max ; r++) + { + this_mv.row = r << 3; + check_here = r * mv_stride + in_what + col_min; + c = col_min; + + while ((c + 3) < col_max) + { + int i; + + fn_ptr->sdx3f(what, what_stride, check_here , in_what_stride, sad_array); + + for (i = 0; i < 3; i++) + { + thissad = sad_array[i]; + + if (thissad < bestsad) + { + this_mv.col = c << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + } + + check_here++; + c++; + } + } + + while (c < col_max) + { + thissad = fn_ptr->sdf(what, what_stride, check_here , in_what_stride, bestsad); + + if (thissad < bestsad) + { + this_mv.col = c << 3; + thissad += vp8_mv_err_cost(&this_mv, ref_mv, mvsadcost, error_per_bit); + + if (thissad < bestsad) + { + bestsad = thissad; + best_mv->row = r; + best_mv->col = c; + bestaddress = check_here; + } + } + + check_here ++; + c ++; + } + + } + + this_mv.row = best_mv->row << 3; + this_mv.col = best_mv->col << 3; + + if (bestsad < INT_MAX) + return fn_ptr->vf(what, what_stride, bestaddress, in_what_stride, (unsigned int *)(&thissad)) + + vp8_mv_err_cost(&this_mv, ref_mv, mvcost, error_per_bit); + else + return INT_MAX; +} +#endif + +#ifdef ENTROPY_STATS +void print_mode_context(void) +{ + FILE *f = fopen("modecont.c", "w"); + int i, j; + + fprintf(f, "#include \"entropy.h\"\n"); + fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); + fprintf(f, "{\n"); + + for (j = 0; j < 6; j++) + { + fprintf(f, " { // %d \n", j); + fprintf(f, " "); + + for (i = 0; i < 4; i++) + { + int overal_prob; + int this_prob; + int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1]; + + // Overall probs + count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; + + if (count) + overal_prob = 256 * mv_mode_cts[i][0] / count; + else + overal_prob = 128; + + if (overal_prob == 0) + overal_prob = 1; + + // context probs + count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; + + if (count) + this_prob = 256 * mv_ref_ct[j][i][0] / count; + else + this_prob = 128; + + if (this_prob == 0) + this_prob = 1; + + fprintf(f, "%5d, ", this_prob); + //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob); + //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob); + } + + fprintf(f, " },\n"); + } + + fprintf(f, "};\n"); + fclose(f); +} + +/* MV ref count ENTROPY_STATS stats code */ +#ifdef ENTROPY_STATS +void init_mv_ref_counts() +{ + vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); + vpx_memset(mv_mode_cts, 0, sizeof(mv_mode_cts)); +} + +void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) +{ + if (m == ZEROMV) + { + ++mv_ref_ct [ct[0]] [0] [0]; + ++mv_mode_cts[0][0]; + } + else + { + ++mv_ref_ct [ct[0]] [0] [1]; + ++mv_mode_cts[0][1]; + + if (m == NEARESTMV) + { + ++mv_ref_ct [ct[1]] [1] [0]; + ++mv_mode_cts[1][0]; + } + else + { + ++mv_ref_ct [ct[1]] [1] [1]; + ++mv_mode_cts[1][1]; + + if (m == NEARMV) + { + ++mv_ref_ct [ct[2]] [2] [0]; + ++mv_mode_cts[2][0]; + } + else + { + ++mv_ref_ct [ct[2]] [2] [1]; + ++mv_mode_cts[2][1]; + + if (m == NEWMV) + { + ++mv_ref_ct [ct[3]] [3] [0]; + ++mv_mode_cts[3][0]; + } + else + { + ++mv_ref_ct [ct[3]] [3] [1]; + ++mv_mode_cts[3][1]; + } + } + } + } +} + +#endif/* END MV ref count ENTROPY_STATS stats code */ + +#endif
diff --git a/vp8/encoder/mcomp.h b/vp8/encoder/mcomp.h new file mode 100644 index 0000000..921206f --- /dev/null +++ b/vp8/encoder/mcomp.h
@@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_MCOMP_H +#define __INC_MCOMP_H + +#include "block.h" +#include "variance.h" + +#ifdef ENTROPY_STATS +extern void init_mv_ref_counts(); +extern void accum_mv_refs(MB_PREDICTION_MODE, const int near_mv_ref_cts[4]); +#endif + + +#define MAX_MVSEARCH_STEPS 8 // The maximum number of steps in a step search given the largest allowed initial step +#define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS+3)) - 8) // Max full pel mv specified in 1/8 pel units +#define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS-1)) // Maximum size of the first step in full pel units + + +extern void print_mode_context(void); +extern int vp8_mv_bit_cost(MV *mv, MV *ref, int *mvcost[2], int Weight); +extern void vp8_init_dsmotion_compensation(MACROBLOCK *x, int stride); +extern void vp8_init3smotion_compensation(MACROBLOCK *x, int stride); + + +extern int vp8_hex_search +( + MACROBLOCK *x, + BLOCK *b, + BLOCKD *d, + MV *ref_mv, + MV *best_mv, + int search_param, + int error_per_bit, + int *num00, + vp8_variance_fn_t vf, + vp8_sad_fn_t sf, + int *mvsadcost[2], + int *mvcost[2] + +); + +typedef int (fractional_mv_step_fp)(MACROBLOCK *x, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]); +extern fractional_mv_step_fp vp8_find_best_sub_pixel_step_iteratively; +extern fractional_mv_step_fp vp8_find_best_sub_pixel_step; +extern fractional_mv_step_fp vp8_find_best_half_pixel_step; +extern fractional_mv_step_fp vp8_skip_fractional_mv_step; + +#define prototype_full_search_sad(sym)\ + int (sym)\ + (\ + MACROBLOCK *x, \ + BLOCK *b, \ + BLOCKD *d, \ + MV *ref_mv, \ + int error_per_bit, \ + int distance, \ + vp8_variance_fn_ptr_t *fn_ptr, \ + int *mvcost[2], \ + int *mvsadcost[2] \ + ) + +#define prototype_diamond_search_sad(sym)\ + int (sym)\ + (\ + MACROBLOCK *x, \ + BLOCK *b, \ + BLOCKD *d, \ + MV *ref_mv, \ + MV *best_mv, \ + int search_param, \ + int error_per_bit, \ + int *num00, \ + vp8_variance_fn_ptr_t *fn_ptr, \ + int *mvsadcost[2], \ + int *mvcost[2] \ + ) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/mcomp_x86.h" +#endif + +typedef prototype_full_search_sad(*vp8_full_search_fn_t); +extern prototype_full_search_sad(vp8_full_search_sad); +extern prototype_full_search_sad(vp8_full_search_sadx3); + +typedef prototype_diamond_search_sad(*vp8_diamond_search_fn_t); +extern prototype_diamond_search_sad(vp8_diamond_search_sad); +extern prototype_diamond_search_sad(vp8_diamond_search_sadx4); + +#ifndef vp8_search_full_search +#define vp8_search_full_search vp8_full_search_sad +#endif +extern prototype_full_search_sad(vp8_search_full_search); + +#ifndef vp8_search_diamond_search +#define vp8_search_diamond_search vp8_diamond_search_sad +#endif +extern prototype_diamond_search_sad(vp8_search_diamond_search); + +typedef struct +{ + prototype_full_search_sad(*full_search); + prototype_diamond_search_sad(*diamond_search); +} vp8_search_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define SEARCH_INVOKE(ctx,fn) (ctx)->fn +#else +#define SEARCH_INVOKE(ctx,fn) vp8_search_##fn +#endif + +#endif
diff --git a/vp8/encoder/modecosts.c b/vp8/encoder/modecosts.c new file mode 100644 index 0000000..73170cf --- /dev/null +++ b/vp8/encoder/modecosts.c
@@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "blockd.h" +#include "onyx_int.h" +#include "treewriter.h" +#include "entropymode.h" + + +void vp8_init_mode_costs(VP8_COMP *c) +{ + VP8_COMMON *x = &c->common; + { + const vp8_tree_p T = vp8_bmode_tree; + + int i = 0; + + do + { + int j = 0; + + do + { + vp8_cost_tokens((int *)c->mb.bmode_costs[i][j], x->kf_bmode_prob[i][j], T); + } + while (++j < VP8_BINTRAMODES); + } + while (++i < VP8_BINTRAMODES); + + vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.bmode_prob, T); + } + vp8_cost_tokens((int *)c->mb.inter_bmode_costs, x->fc.sub_mv_ref_prob, vp8_sub_mv_ref_tree); + + vp8_cost_tokens(c->mb.mbmode_cost[1], x->fc.ymode_prob, vp8_ymode_tree); + vp8_cost_tokens(c->mb.mbmode_cost[0], x->kf_ymode_prob, vp8_kf_ymode_tree); + + vp8_cost_tokens(c->mb.intra_uv_mode_cost[1], x->fc.uv_mode_prob, vp8_uv_mode_tree); + vp8_cost_tokens(c->mb.intra_uv_mode_cost[0], x->kf_uv_mode_prob, vp8_uv_mode_tree); +}
diff --git a/vp8/encoder/modecosts.h b/vp8/encoder/modecosts.h new file mode 100644 index 0000000..5ade265 --- /dev/null +++ b/vp8/encoder/modecosts.h
@@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_MODECOSTS_H +#define __INC_MODECOSTS_H + +void vp8_init_mode_costs(VP8_COMP *x); + +#endif
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c new file mode 100644 index 0000000..7662720 --- /dev/null +++ b/vp8/encoder/onyx_if.c
@@ -0,0 +1,5428 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxc_int.h" +#include "onyx_int.h" +#include "systemdependent.h" +#include "quantize.h" +#include "alloccommon.h" +#include "mcomp.h" +#include "firstpass.h" +#include "psnr.h" +#include "vpx_scale/vpxscale.h" +#include "extend.h" +#include "ratectrl.h" +#include "quant_common.h" +#include "segmentation_common.h" +#include "g_common.h" +#include "vpx_scale/yv12extend.h" +#include "postproc.h" +#include "vpx_mem/vpx_mem.h" +#include "swapyv12buffer.h" +#include "threading.h" +#include "vpx_ports/vpx_timer.h" +#include <math.h> +#include <stdio.h> +#include <limits.h> + +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#define RTCD(x) &cpi->common.rtcd.x +#else +#define IF_RTCD(x) NULL +#define RTCD(x) NULL +#endif + +extern void vp8cx_init_mv_bits_sadcost(); +extern void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi); +extern void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val); +extern void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi); + +extern void vp8_init_loop_filter(VP8_COMMON *cm); +extern void vp8_loop_filter_frame(VP8_COMMON *cm, MACROBLOCKD *mbd, int filt_val); +extern void vp8_loop_filter_frame_yonly(VP8_COMMON *cm, MACROBLOCKD *mbd, int filt_val, int sharpness_lvl); +extern void vp8_dmachine_specific_config(VP8_COMP *cpi); +extern void vp8_cmachine_specific_config(VP8_COMP *cpi); +extern void vp8_calc_auto_iframe_target_size(VP8_COMP *cpi); +extern void vp8_deblock_frame(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *post, int filt_lvl, int low_var_thresh, int flag); +extern void print_parms(VP8_CONFIG *ocf, char *filenam); +extern unsigned int vp8_get_processor_freq(); +extern void print_tree_update_probs(); +extern void vp8cx_create_encoder_threads(VP8_COMP *cpi); +extern void vp8cx_remove_encoder_threads(VP8_COMP *cpi); +#if HAVE_ARMV7 +extern void vp8_yv12_copy_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); +extern void vp8_yv12_copy_src_frame_func_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); +#endif + +int vp8_estimate_entropy_savings(VP8_COMP *cpi); +int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd); +int vp8_calc_low_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd); + + +static void mode_ref_lf_test_function(VP8_COMP *cpi); + +extern const int vp8_gf_interval_table[101]; + +#if CONFIG_PSNR +#include "math.h" + +extern double vp8_calc_ssim +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + int lumamask, + double *weight +); + +extern double vp8_calc_ssimg +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + double *ssim_y, + double *ssim_u, + double *ssim_v +); + + +#endif + + +#ifdef OUTPUT_YUV_SRC +FILE *yuv_file; +#endif + +#if 0 +FILE *framepsnr; +FILE *kf_list; +FILE *keyfile; +#endif + +#if 0 +extern int skip_true_count; +extern int skip_false_count; +#endif + + +#ifdef ENTROPY_STATS +extern int intra_mode_stats[10][10][10]; +#endif + +#ifdef SPEEDSTATS +unsigned int frames_at_speed[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned int tot_pm = 0; +unsigned int cnt_pm = 0; +unsigned int tot_ef = 0; +unsigned int cnt_ef = 0; +#endif + +#ifdef MODE_STATS +extern unsigned __int64 Sectionbits[50]; +extern int y_modes[5] ; +extern int uv_modes[4] ; +extern int b_modes[10] ; + +extern int inter_y_modes[10] ; +extern int inter_uv_modes[4] ; +extern unsigned int inter_b_modes[15]; +#endif + +extern void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); +extern void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); +extern void (*vp8_fast_fdct4x4)(short *input, short *output, int pitch); +extern void (*vp8_fast_fdct8x4)(short *input, short *output, int pitch); + +extern const int vp8_bits_per_mb[2][QINDEX_RANGE]; + +extern const int qrounding_factors[129]; +extern const int qzbin_factors[129]; +extern void vp8cx_init_quantizer(VP8_COMP *cpi); +extern const int vp8cx_base_skip_false_prob[128]; + + +void vp8_initialize() +{ + static int init_done = 0; + + if (!init_done) + { + vp8_scale_machine_specific_config(); + vp8_initialize_common(); + //vp8_dmachine_specific_config(); + vp8_tokenize_initialize(); + + vp8cx_init_mv_bits_sadcost(); + init_done = 1; + } +} +#ifdef PACKET_TESTING +extern FILE *vpxlogc; +#endif + +static void setup_features(VP8_COMP *cpi) +{ + // Set up default state for MB feature flags + cpi->mb.e_mbd.segmentation_enabled = 0; + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + vpx_memset(cpi->mb.e_mbd.mb_segment_tree_probs, 255, sizeof(cpi->mb.e_mbd.mb_segment_tree_probs)); + vpx_memset(cpi->mb.e_mbd.segment_feature_data, 0, sizeof(cpi->mb.e_mbd.segment_feature_data)); + + cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + vpx_memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + + // jbb trial ! + mode_ref_lf_test_function(cpi); + +} + + +void vp8_dealloc_compressor_data(VP8_COMP *cpi) +{ + + // Delete sementation map + if (cpi->segmentation_map != 0) + vpx_free(cpi->segmentation_map); + + cpi->segmentation_map = 0; + + if (cpi->active_map != 0) + vpx_free(cpi->active_map); + + cpi->active_map = 0; + + // Delete first pass motion map + if (cpi->fp_motion_map != 0) + vpx_free(cpi->fp_motion_map); + + cpi->fp_motion_map = 0; + + vp8_de_alloc_frame_buffers(&cpi->common); + + vp8_yv12_de_alloc_frame_buffer(&cpi->last_frame_uf); + vp8_yv12_de_alloc_frame_buffer(&cpi->scaled_source); +#if VP8_TEMPORAL_ALT_REF + vp8_yv12_de_alloc_frame_buffer(&cpi->alt_ref_buffer.source_buffer); +#endif + { + int i; + + for (i = 0; i < MAX_LAG_BUFFERS; i++) + vp8_yv12_de_alloc_frame_buffer(&cpi->src_buffer[i].source_buffer); + + cpi->source_buffer_count = 0; + } + + vpx_free(cpi->tok); + cpi->tok = 0; + +} + +static void enable_segmentation(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Set the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 1; + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} +static void disable_segmentation(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Clear the appropriate feature bit + cpi->mb.e_mbd.segmentation_enabled = 0; +} + +// Valid values for a segment are 0 to 3 +// Segmentation map is arrange as [Rows][Columns] +static void set_segmentation_map(VP8_PTR ptr, unsigned char *segmentation_map) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + // Copy in the new segmentation map + vpx_memcpy(cpi->segmentation_map, segmentation_map, (cpi->common.mb_rows * cpi->common.mb_cols)); + + // Signal that the map should be updated. + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; +} + +// The values given for each segment can be either deltas (from the default value chosen for the frame) or absolute values. +// +// Valid range for abs values is (0-127 for MB_LVL_ALT_Q) , (0-63 for SEGMENT_ALT_LF) +// Valid range for delta values are (+/-127 for MB_LVL_ALT_Q) , (+/-63 for SEGMENT_ALT_LF) +// +// abs_delta = SEGMENT_DELTADATA (deltas) abs_delta = SEGMENT_ABSDATA (use the absolute values given). +// +// +static void set_segment_data(VP8_PTR ptr, signed char *feature_data, unsigned char abs_delta) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + cpi->mb.e_mbd.mb_segement_abs_delta = abs_delta; + vpx_memcpy(cpi->segment_feature_data, feature_data, sizeof(cpi->segment_feature_data)); +} + + +static void segmentation_test_function(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + unsigned char *seg_map; + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + int i, j; + + // Create a temporary map for segmentation data. + CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + + // MB loop to set local segmentation map + /*for ( i = 0; i < cpi->common.mb_rows; i++ ) + { + for ( j = 0; j < cpi->common.mb_cols; j++ ) + { + //seg_map[(i*cpi->common.mb_cols) + j] = (j % 2) + ((i%2)* 2); + //if ( j < cpi->common.mb_cols/2 ) + + // Segment 1 around the edge else 0 + if ( (i == 0) || (j == 0) || (i == (cpi->common.mb_rows-1)) || (j == (cpi->common.mb_cols-1)) ) + seg_map[(i*cpi->common.mb_cols) + j] = 1; + //else if ( (i < 2) || (j < 2) || (i > (cpi->common.mb_rows-3)) || (j > (cpi->common.mb_cols-3)) ) + // seg_map[(i*cpi->common.mb_cols) + j] = 2; + //else if ( (i < 5) || (j < 5) || (i > (cpi->common.mb_rows-6)) || (j > (cpi->common.mb_cols-6)) ) + // seg_map[(i*cpi->common.mb_cols) + j] = 3; + else + seg_map[(i*cpi->common.mb_cols) + j] = 0; + } + }*/ + + // Set the segmentation Map + set_segmentation_map(ptr, seg_map); + + // Activate segmentation. + enable_segmentation(ptr); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = 0; + feature_data[MB_LVL_ALT_Q][1] = 4; + feature_data[MB_LVL_ALT_Q][2] = 0; + feature_data[MB_LVL_ALT_Q][3] = 0; + // Set up the loop segment data + feature_data[MB_LVL_ALT_LF][0] = 0; + feature_data[MB_LVL_ALT_LF][1] = 0; + feature_data[MB_LVL_ALT_LF][2] = 0; + feature_data[MB_LVL_ALT_LF][3] = 0; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data(ptr, &feature_data[0][0], SEGMENT_DELTADATA); + + // Delete sementation map + if (seg_map != 0) + vpx_free(seg_map); + + seg_map = 0; + +} + +// A simple function to cyclically refresh the background at a lower Q +static void cyclic_background_refresh(VP8_COMP *cpi, int Q, int lf_adjustment) +{ + unsigned char *seg_map; + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + int i; + int block_count = cpi->cyclic_refresh_mode_max_mbs_perframe; + int mbs_in_frame = cpi->common.mb_rows * cpi->common.mb_cols; + + // Create a temporary map for segmentation data. + CHECK_MEM_ERROR(seg_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + + cpi->cyclic_refresh_q = Q; + + for (i = Q; i > 0; i--) + { + if (vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*(Q + 128)) / 64)) + //if ( vp8_bits_per_mb[cpi->common.frame_type][i] >= ((vp8_bits_per_mb[cpi->common.frame_type][Q]*((2*Q)+96))/64) ) + { + break; + } + } + + cpi->cyclic_refresh_q = i; + + // Only update for inter frames + if (cpi->common.frame_type != KEY_FRAME) + { + // Cycle through the macro_block rows + // MB loop to set local segmentation map + for (i = cpi->cyclic_refresh_mode_index; i < mbs_in_frame; i++) + { + // If the MB is as a candidate for clean up then mark it for possible boost/refresh (segment 1) + // The segment id may get reset to 0 later if the MB gets coded anything other than last frame 0,0 + // as only (last frame 0,0) MBs are eligable for refresh : that is to say Mbs likely to be background blocks. + if (cpi->cyclic_refresh_map[i] == 0) + { + seg_map[i] = 1; + } + else + { + seg_map[i] = 0; + + // Skip blocks that have been refreshed recently anyway. + if (cpi->cyclic_refresh_map[i] < 0) + //cpi->cyclic_refresh_map[i] = cpi->cyclic_refresh_map[i] / 16; + cpi->cyclic_refresh_map[i]++; + } + + + if (block_count > 0) + block_count--; + else + break; + + } + + // If we have gone through the frame reset to the start + cpi->cyclic_refresh_mode_index = i; + + if (cpi->cyclic_refresh_mode_index >= mbs_in_frame) + cpi->cyclic_refresh_mode_index = 0; + } + + // Set the segmentation Map + set_segmentation_map((VP8_PTR)cpi, seg_map); + + // Activate segmentation. + enable_segmentation((VP8_PTR)cpi); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = 0; + feature_data[MB_LVL_ALT_Q][1] = (cpi->cyclic_refresh_q - Q); + feature_data[MB_LVL_ALT_Q][2] = 0; + feature_data[MB_LVL_ALT_Q][3] = 0; + + // Set up the loop segment data + feature_data[MB_LVL_ALT_LF][0] = 0; + feature_data[MB_LVL_ALT_LF][1] = lf_adjustment; + feature_data[MB_LVL_ALT_LF][2] = 0; + feature_data[MB_LVL_ALT_LF][3] = 0; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data((VP8_PTR)cpi, &feature_data[0][0], SEGMENT_DELTADATA); + + // Delete sementation map + if (seg_map != 0) + vpx_free(seg_map); + + seg_map = 0; + +} + +static void mode_ref_lf_test_function(VP8_COMP *cpi) +{ + cpi->mb.e_mbd.mode_ref_lf_delta_enabled = 1; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 1; + + vpx_memset(cpi->mb.e_mbd.ref_lf_deltas, 0, sizeof(cpi->mb.e_mbd.ref_lf_deltas)); + vpx_memset(cpi->mb.e_mbd.mode_lf_deltas, 0, sizeof(cpi->mb.e_mbd.mode_lf_deltas)); + + // Test of ref frame deltas + cpi->mb.e_mbd.ref_lf_deltas[INTRA_FRAME] = 2; + cpi->mb.e_mbd.ref_lf_deltas[LAST_FRAME] = 0; + cpi->mb.e_mbd.ref_lf_deltas[GOLDEN_FRAME] = -2; + cpi->mb.e_mbd.ref_lf_deltas[ALTREF_FRAME] = -2; + + cpi->mb.e_mbd.mode_lf_deltas[0] = 4; // BPRED + cpi->mb.e_mbd.mode_lf_deltas[1] = -2; // Zero + cpi->mb.e_mbd.mode_lf_deltas[2] = 2; // New mv + cpi->mb.e_mbd.mode_lf_deltas[3] = 4; // Split mv +} + +void vp8_set_speed_features(VP8_COMP *cpi) +{ + SPEED_FEATURES *sf = &cpi->sf; + int Mode = cpi->compressor_speed; + int Speed = cpi->Speed; + int i; + VP8_COMMON *cm = &cpi->common; + + // Initialise default mode frequency sampling variables + for (i = 0; i < MAX_MODES; i ++) + { + cpi->mode_check_freq[i] = 0; + cpi->mode_test_hit_counts[i] = 0; + cpi->mode_chosen_counts[i] = 0; + } + + cpi->mbs_tested_so_far = 0; + + // best quality + sf->RD = 1; + sf->search_method = NSTEP; + sf->improved_quant = 1; + sf->improved_dct = 1; + sf->auto_filter = 1; + sf->recode_loop = 1; + sf->quarter_pixel_search = 1; + sf->half_pixel_search = 1; + sf->full_freq[0] = 7; + sf->full_freq[1] = 7; + sf->min_fs_radius = 8; + sf->max_fs_radius = 32; + sf->iterative_sub_pixel = 1; + sf->optimize_coefficients = 1; + + sf->first_step = 0; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + + cpi->do_full[0] = 0; + cpi->do_full[1] = 0; + + // default thresholds to 0 + for (i = 0; i < MAX_MODES; i++) + sf->thresh_mult[i] = 0; + + switch (Mode) + { +#if !(CONFIG_REALTIME_ONLY) + case 0: // best quality mode + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_ZEROG ] = 0; + sf->thresh_mult[THR_ZEROA ] = 0; + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_NEARESTG ] = 0; + sf->thresh_mult[THR_NEARESTA ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_NEARG ] = 0; + sf->thresh_mult[THR_NEARA ] = 0; + + sf->thresh_mult[THR_DC ] = 0; + + sf->thresh_mult[THR_V_PRED ] = 1000; + sf->thresh_mult[THR_H_PRED ] = 1000; + sf->thresh_mult[THR_B_PRED ] = 2000; + sf->thresh_mult[THR_TM ] = 1000; + + sf->thresh_mult[THR_NEWMV ] = 1000; + sf->thresh_mult[THR_NEWG ] = 1000; + sf->thresh_mult[THR_NEWA ] = 1000; + + sf->thresh_mult[THR_SPLITMV ] = 2500; + sf->thresh_mult[THR_SPLITG ] = 5000; + sf->thresh_mult[THR_SPLITA ] = 5000; + + sf->full_freq[0] = 7; + sf->full_freq[1] = 15; + + sf->first_step = 0; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + + if (!(cpi->ref_frame_flags & VP8_LAST_FLAG)) + { + sf->thresh_mult[THR_NEWMV ] = INT_MAX; + sf->thresh_mult[THR_NEARESTMV] = INT_MAX; + sf->thresh_mult[THR_ZEROMV ] = INT_MAX; + sf->thresh_mult[THR_NEARMV ] = INT_MAX; + sf->thresh_mult[THR_SPLITMV ] = INT_MAX; + } + + if (!(cpi->ref_frame_flags & VP8_GOLD_FLAG)) + { + sf->thresh_mult[THR_NEARESTG ] = INT_MAX; + sf->thresh_mult[THR_ZEROG ] = INT_MAX; + sf->thresh_mult[THR_NEARG ] = INT_MAX; + sf->thresh_mult[THR_NEWG ] = INT_MAX; + sf->thresh_mult[THR_SPLITG ] = INT_MAX; + } + else if (!(cpi->ref_frame_flags & VP8_ALT_FLAG)) + { + sf->thresh_mult[THR_NEARESTA ] = INT_MAX; + sf->thresh_mult[THR_ZEROA ] = INT_MAX; + sf->thresh_mult[THR_NEARA ] = INT_MAX; + sf->thresh_mult[THR_NEWA ] = INT_MAX; + sf->thresh_mult[THR_SPLITA ] = INT_MAX; + } + + break; + case 1: + case 3: + sf->optimize_coefficients = 0; + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_DC ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_V_PRED ] = 1000; + sf->thresh_mult[THR_H_PRED ] = 1000; + sf->thresh_mult[THR_B_PRED ] = 2500; + sf->thresh_mult[THR_TM ] = 1000; + + sf->thresh_mult[THR_NEARESTG ] = 1000; + sf->thresh_mult[THR_NEARESTA ] = 1000; + + sf->thresh_mult[THR_ZEROG ] = 1000; + sf->thresh_mult[THR_ZEROA ] = 1000; + sf->thresh_mult[THR_NEARG ] = 1000; + sf->thresh_mult[THR_NEARA ] = 1000; + + sf->thresh_mult[THR_NEWMV ] = 1500; + sf->thresh_mult[THR_NEWG ] = 1500; + sf->thresh_mult[THR_NEWA ] = 1500; + + sf->thresh_mult[THR_SPLITMV ] = 5000; + sf->thresh_mult[THR_SPLITG ] = 10000; + sf->thresh_mult[THR_SPLITA ] = 10000; + + sf->full_freq[0] = 15; + sf->full_freq[1] = 31; + + sf->first_step = 0; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + + if (!(cpi->ref_frame_flags & VP8_LAST_FLAG)) + { + sf->thresh_mult[THR_NEWMV ] = INT_MAX; + sf->thresh_mult[THR_NEARESTMV] = INT_MAX; + sf->thresh_mult[THR_ZEROMV ] = INT_MAX; + sf->thresh_mult[THR_NEARMV ] = INT_MAX; + sf->thresh_mult[THR_SPLITMV ] = INT_MAX; + } + else if (!(cpi->ref_frame_flags & VP8_GOLD_FLAG)) + { + sf->thresh_mult[THR_NEARESTG ] = INT_MAX; + sf->thresh_mult[THR_ZEROG ] = INT_MAX; + sf->thresh_mult[THR_NEARG ] = INT_MAX; + sf->thresh_mult[THR_NEWG ] = INT_MAX; + sf->thresh_mult[THR_SPLITG ] = INT_MAX; + } + else if (!(cpi->ref_frame_flags & VP8_ALT_FLAG)) + { + sf->thresh_mult[THR_NEARESTA ] = INT_MAX; + sf->thresh_mult[THR_ZEROA ] = INT_MAX; + sf->thresh_mult[THR_NEARA ] = INT_MAX; + sf->thresh_mult[THR_NEWA ] = INT_MAX; + sf->thresh_mult[THR_SPLITA ] = INT_MAX; + } + + if (Speed > 0) + { + cpi->mode_check_freq[THR_SPLITG] = 4; + cpi->mode_check_freq[THR_SPLITA] = 4; + cpi->mode_check_freq[THR_SPLITMV] = 2; + + sf->thresh_mult[THR_TM ] = 1500; + sf->thresh_mult[THR_V_PRED ] = 1500; + sf->thresh_mult[THR_H_PRED ] = 1500; + sf->thresh_mult[THR_B_PRED ] = 5000; + + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEWMV ] = 2000; + sf->thresh_mult[THR_SPLITMV ] = 10000; + } + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 1500; + sf->thresh_mult[THR_ZEROG ] = 1500; + sf->thresh_mult[THR_NEARG ] = 1500; + sf->thresh_mult[THR_NEWG ] = 2000; + sf->thresh_mult[THR_SPLITG ] = 20000; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 1500; + sf->thresh_mult[THR_ZEROA ] = 1500; + sf->thresh_mult[THR_NEARA ] = 1500; + sf->thresh_mult[THR_NEWA ] = 2000; + sf->thresh_mult[THR_SPLITA ] = 20000; + } + + sf->improved_quant = 0; + sf->improved_dct = 0; + + sf->first_step = 1; + sf->max_step_search_steps = MAX_MVSEARCH_STEPS; + } + + if (Speed > 1) + { + cpi->mode_check_freq[THR_SPLITG] = 15; + cpi->mode_check_freq[THR_SPLITA] = 15; + cpi->mode_check_freq[THR_SPLITMV] = 7; + + sf->thresh_mult[THR_TM ] = 2000; + sf->thresh_mult[THR_V_PRED ] = 2000; + sf->thresh_mult[THR_H_PRED ] = 2000; + sf->thresh_mult[THR_B_PRED ] = 7500; + + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEWMV ] = 2000; + sf->thresh_mult[THR_SPLITMV ] = 25000; + } + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 2000; + sf->thresh_mult[THR_ZEROG ] = 2000; + sf->thresh_mult[THR_NEARG ] = 2000; + sf->thresh_mult[THR_NEWG ] = 2500; + sf->thresh_mult[THR_SPLITG ] = 50000; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 2000; + sf->thresh_mult[THR_ZEROA ] = 2000; + sf->thresh_mult[THR_NEARA ] = 2000; + sf->thresh_mult[THR_NEWA ] = 2500; + sf->thresh_mult[THR_SPLITA ] = 50000; + } + + // Only do recode loop on key frames and golden frames + sf->recode_loop = 2; + + sf->full_freq[0] = 31; + sf->full_freq[1] = 63; + + } + + if (Speed > 2) + { + sf->auto_filter = 0; // Faster selection of loop filter + cpi->mode_check_freq[THR_V_PRED] = 2; + cpi->mode_check_freq[THR_H_PRED] = 2; + cpi->mode_check_freq[THR_B_PRED] = 2; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + cpi->mode_check_freq[THR_NEARG] = 2; + cpi->mode_check_freq[THR_NEWG] = 4; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + cpi->mode_check_freq[THR_NEARA] = 2; + cpi->mode_check_freq[THR_NEWA] = 4; + } + + sf->thresh_mult[THR_SPLITA ] = INT_MAX; + sf->thresh_mult[THR_SPLITG ] = INT_MAX; + sf->thresh_mult[THR_SPLITMV ] = INT_MAX; + + sf->full_freq[0] = 63; + sf->full_freq[1] = 127; + } + + if (Speed > 3) + { + cpi->mode_check_freq[THR_V_PRED] = 0; + cpi->mode_check_freq[THR_H_PRED] = 0; + cpi->mode_check_freq[THR_B_PRED] = 0; + cpi->mode_check_freq[THR_NEARG] = 0; + cpi->mode_check_freq[THR_NEWG] = 0; + cpi->mode_check_freq[THR_NEARA] = 0; + cpi->mode_check_freq[THR_NEWA] = 0; + + sf->auto_filter = 1; + sf->recode_loop = 0; // recode loop off + sf->RD = 0; // Turn rd off + sf->full_freq[0] = INT_MAX; + sf->full_freq[1] = INT_MAX; + } + + if (Speed > 4) + { + sf->auto_filter = 0; // Faster selection of loop filter + + cpi->mode_check_freq[THR_V_PRED] = 2; + cpi->mode_check_freq[THR_H_PRED] = 2; + cpi->mode_check_freq[THR_B_PRED] = 2; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + cpi->mode_check_freq[THR_NEARG] = 2; + cpi->mode_check_freq[THR_NEWG] = 4; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + cpi->mode_check_freq[THR_NEARA] = 2; + cpi->mode_check_freq[THR_NEWA] = 4; + } + + if (cpi->ref_frame_flags & VP8_LAST_FLAG & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 2000; + sf->thresh_mult[THR_ZEROG ] = 2000; + sf->thresh_mult[THR_NEARG ] = 2000; + sf->thresh_mult[THR_NEWG ] = 4000; + } + + if (cpi->ref_frame_flags & VP8_LAST_FLAG & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 2000; + sf->thresh_mult[THR_ZEROA ] = 2000; + sf->thresh_mult[THR_NEARA ] = 2000; + sf->thresh_mult[THR_NEWA ] = 4000; + } + } + + break; +#endif + case 2: + sf->optimize_coefficients = 0; + sf->recode_loop = 0; + sf->auto_filter = 1; + sf->iterative_sub_pixel = 1; + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_DC ] = 0; + sf->thresh_mult[THR_TM ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_V_PRED ] = 1000; + sf->thresh_mult[THR_H_PRED ] = 1000; + sf->thresh_mult[THR_B_PRED ] = 2500; + sf->thresh_mult[THR_NEARESTG ] = 1000; + sf->thresh_mult[THR_ZEROG ] = 1000; + sf->thresh_mult[THR_NEARG ] = 1000; + sf->thresh_mult[THR_NEARESTA ] = 1000; + sf->thresh_mult[THR_ZEROA ] = 1000; + sf->thresh_mult[THR_NEARA ] = 1000; + sf->thresh_mult[THR_NEWMV ] = 2000; + sf->thresh_mult[THR_NEWG ] = 2000; + sf->thresh_mult[THR_NEWA ] = 2000; + sf->thresh_mult[THR_SPLITMV ] = 5000; + sf->thresh_mult[THR_SPLITG ] = 10000; + sf->thresh_mult[THR_SPLITA ] = 10000; + sf->full_freq[0] = 15; + sf->full_freq[1] = 31; + sf->search_method = NSTEP; + + if (!cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEWMV ] = INT_MAX; + sf->thresh_mult[THR_NEARESTMV] = INT_MAX; + sf->thresh_mult[THR_ZEROMV ] = INT_MAX; + sf->thresh_mult[THR_NEARMV ] = INT_MAX; + sf->thresh_mult[THR_SPLITMV ] = INT_MAX; + } + + if (!cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = INT_MAX; + sf->thresh_mult[THR_ZEROG ] = INT_MAX; + sf->thresh_mult[THR_NEARG ] = INT_MAX; + sf->thresh_mult[THR_NEWG ] = INT_MAX; + sf->thresh_mult[THR_SPLITG ] = INT_MAX; + } + + if (!cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = INT_MAX; + sf->thresh_mult[THR_ZEROA ] = INT_MAX; + sf->thresh_mult[THR_NEARA ] = INT_MAX; + sf->thresh_mult[THR_NEWA ] = INT_MAX; + sf->thresh_mult[THR_SPLITA ] = INT_MAX; + } + + if (Speed > 0) + { + cpi->mode_check_freq[THR_SPLITG] = 4; + cpi->mode_check_freq[THR_SPLITA] = 4; + cpi->mode_check_freq[THR_SPLITMV] = 2; + + sf->thresh_mult[THR_DC ] = 0; + sf->thresh_mult[THR_TM ] = 1000; + sf->thresh_mult[THR_V_PRED ] = 2000; + sf->thresh_mult[THR_H_PRED ] = 2000; + sf->thresh_mult[THR_B_PRED ] = 5000; + + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEARESTMV] = 0; + sf->thresh_mult[THR_ZEROMV ] = 0; + sf->thresh_mult[THR_NEARMV ] = 0; + sf->thresh_mult[THR_NEWMV ] = 2000; + sf->thresh_mult[THR_SPLITMV ] = 10000; + } + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 1000; + sf->thresh_mult[THR_ZEROG ] = 1000; + sf->thresh_mult[THR_NEARG ] = 1000; + sf->thresh_mult[THR_NEWG ] = 2000; + sf->thresh_mult[THR_SPLITG ] = 20000; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 1000; + sf->thresh_mult[THR_ZEROA ] = 1000; + sf->thresh_mult[THR_NEARA ] = 1000; + sf->thresh_mult[THR_NEWA ] = 2000; + sf->thresh_mult[THR_SPLITA ] = 20000; + } + + sf->improved_quant = 0; + sf->improved_dct = 0; + } + + if (Speed > 1) + { + cpi->mode_check_freq[THR_SPLITMV] = 7; + cpi->mode_check_freq[THR_SPLITG] = 15; + cpi->mode_check_freq[THR_SPLITA] = 15; + + sf->thresh_mult[THR_TM ] = 2000; + sf->thresh_mult[THR_V_PRED ] = 2000; + sf->thresh_mult[THR_H_PRED ] = 2000; + sf->thresh_mult[THR_B_PRED ] = 5000; + + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEWMV ] = 2000; + sf->thresh_mult[THR_SPLITMV ] = 25000; + } + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 2000; + sf->thresh_mult[THR_ZEROG ] = 2000; + sf->thresh_mult[THR_NEARG ] = 2000; + sf->thresh_mult[THR_NEWG ] = 2500; + sf->thresh_mult[THR_SPLITG ] = 50000; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 2000; + sf->thresh_mult[THR_ZEROA ] = 2000; + sf->thresh_mult[THR_NEARA ] = 2000; + sf->thresh_mult[THR_NEWA ] = 2500; + sf->thresh_mult[THR_SPLITA ] = 50000; + } + + sf->full_freq[0] = 31; + sf->full_freq[1] = 63; + } + + if (Speed > 2) + { + sf->auto_filter = 0; // Faster selection of loop filter + + cpi->mode_check_freq[THR_V_PRED] = 2; + cpi->mode_check_freq[THR_H_PRED] = 2; + cpi->mode_check_freq[THR_B_PRED] = 2; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + cpi->mode_check_freq[THR_NEARG] = 2; + cpi->mode_check_freq[THR_NEWG] = 4; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + cpi->mode_check_freq[THR_NEARA] = 2; + cpi->mode_check_freq[THR_NEWA] = 4; + } + + sf->thresh_mult[THR_SPLITMV ] = INT_MAX; + sf->thresh_mult[THR_SPLITG ] = INT_MAX; + sf->thresh_mult[THR_SPLITA ] = INT_MAX; + + sf->full_freq[0] = 63; + sf->full_freq[1] = 127; + } + + if (Speed > 3) + { + sf->RD = 0; + sf->full_freq[0] = INT_MAX; + sf->full_freq[1] = INT_MAX; + + sf->auto_filter = 1; + } + + if (Speed > 4) + { + sf->auto_filter = 0; // Faster selection of loop filter + +#if CONFIG_REALTIME_ONLY + sf->search_method = HEX; +#else + sf->search_method = DIAMOND; +#endif + + cpi->mode_check_freq[THR_V_PRED] = 4; + cpi->mode_check_freq[THR_H_PRED] = 4; + cpi->mode_check_freq[THR_B_PRED] = 4; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + cpi->mode_check_freq[THR_NEARG] = 2; + cpi->mode_check_freq[THR_NEWG] = 4; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + cpi->mode_check_freq[THR_NEARA] = 2; + cpi->mode_check_freq[THR_NEWA] = 4; + } + + sf->thresh_mult[THR_TM ] = 2000; + sf->thresh_mult[THR_B_PRED ] = 5000; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEARESTG ] = 2000; + sf->thresh_mult[THR_ZEROG ] = 2000; + sf->thresh_mult[THR_NEARG ] = 2000; + sf->thresh_mult[THR_NEWG ] = 4000; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEARESTA ] = 2000; + sf->thresh_mult[THR_ZEROA ] = 2000; + sf->thresh_mult[THR_NEARA ] = 2000; + sf->thresh_mult[THR_NEWA ] = 4000; + } + } + + if (Speed > 5) + { + // Disable split MB intra prediction mode + sf->thresh_mult[THR_B_PRED] = INT_MAX; + } + + if (Speed > 6) + { + unsigned int i, sum = 0; + unsigned int total_mbs = cm->MBs; + int thresh; + int total_skip; + + int min = 2000; + sf->iterative_sub_pixel = 0; + + if (cpi->oxcf.encode_breakout > 2000) + min = cpi->oxcf.encode_breakout; + + min >>= 7; + + for (i = 0; i < min; i++) + { + sum += cpi->error_bins[i]; + } + + total_skip = sum; + sum = 0; + + // i starts from 2 to make sure thresh started from 2048 + for (; i < 1024; i++) + { + sum += cpi->error_bins[i]; + + if (10 * sum >= (unsigned int)(cpi->Speed - 6)*(total_mbs - total_skip)) + break; + } + + i--; + thresh = (i << 7); + + if (thresh < 2000) + thresh = 2000; + + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + sf->thresh_mult[THR_NEWMV] = thresh; + sf->thresh_mult[THR_NEARESTMV ] = thresh >> 1; + sf->thresh_mult[THR_NEARMV ] = thresh >> 1; + } + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + sf->thresh_mult[THR_NEWG] = thresh << 1; + sf->thresh_mult[THR_NEARESTG ] = thresh; + sf->thresh_mult[THR_NEARG ] = thresh; + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + sf->thresh_mult[THR_NEWA] = thresh << 1; + sf->thresh_mult[THR_NEARESTA ] = thresh; + sf->thresh_mult[THR_NEARA ] = thresh; + } + + // Disable other intra prediction modes + sf->thresh_mult[THR_TM] = INT_MAX; + sf->thresh_mult[THR_V_PRED] = INT_MAX; + sf->thresh_mult[THR_H_PRED] = INT_MAX; + + } + + if (Speed > 8) + { + sf->quarter_pixel_search = 0; + } + + if (Speed > 9) + { + int Tmp = cpi->Speed - 8; + + if (Tmp > 4) + Tmp = 4; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + cpi->mode_check_freq[THR_ZEROG] = 1 << (Tmp - 1); + cpi->mode_check_freq[THR_NEARESTG] = 1 << (Tmp - 1); + cpi->mode_check_freq[THR_NEARG] = 1 << Tmp; + cpi->mode_check_freq[THR_NEWG] = 1 << (Tmp + 1); + } + + if (cpi->ref_frame_flags & VP8_ALT_FLAG) + { + cpi->mode_check_freq[THR_ZEROA] = 1 << (Tmp - 1); + cpi->mode_check_freq[THR_NEARESTA] = 1 << (Tmp - 1); + cpi->mode_check_freq[THR_NEARA] = 1 << Tmp; + cpi->mode_check_freq[THR_NEWA] = 1 << (Tmp + 1); + } + + cpi->mode_check_freq[THR_NEWMV] = 1 << (Tmp - 1); + } + + cm->filter_type = NORMAL_LOOPFILTER; + + if (Speed >= 14) + cm->filter_type = SIMPLE_LOOPFILTER; + + if (Speed >= 15) + { + sf->half_pixel_search = 0; // This has a big hit on quality. Last resort + } + + vpx_memset(cpi->error_bins, 0, sizeof(cpi->error_bins)); + + }; + + if (cpi->sf.search_method == NSTEP) + { + vp8_init3smotion_compensation(&cpi->mb, cm->last_frame.y_stride); + } + else if (cpi->sf.search_method == DIAMOND) + { + vp8_init_dsmotion_compensation(&cpi->mb, cm->last_frame.y_stride); + } + + if (cpi->sf.improved_dct) + { + cpi->mb.vp8_short_fdct8x4 = FDCT_INVOKE(&cpi->rtcd.fdct, short8x4); + cpi->mb.vp8_short_fdct4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, short4x4); + cpi->mb.short_fdct8x4rd = FDCT_INVOKE(&cpi->rtcd.fdct, short8x4); + cpi->mb.short_fdct4x4rd = FDCT_INVOKE(&cpi->rtcd.fdct, short4x4); + } + else + { + cpi->mb.vp8_short_fdct8x4 = FDCT_INVOKE(&cpi->rtcd.fdct, fast8x4); + cpi->mb.vp8_short_fdct4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, fast4x4); + cpi->mb.short_fdct8x4rd = FDCT_INVOKE(&cpi->rtcd.fdct, fast8x4); + cpi->mb.short_fdct4x4rd = FDCT_INVOKE(&cpi->rtcd.fdct, fast4x4); + } + + cpi->mb.vp8_short_fdct4x4_ptr = FDCT_INVOKE(&cpi->rtcd.fdct, short4x4); + cpi->mb.short_walsh4x4 = FDCT_INVOKE(&cpi->rtcd.fdct, walsh_short4x4); + + if (cpi->sf.improved_quant) + { + cpi->mb.quantize_b = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb); + cpi->mb.quantize_brd = QUANTIZE_INVOKE(&cpi->rtcd.quantize, quantb); + } + else + { + cpi->mb.quantize_b = QUANTIZE_INVOKE(&cpi->rtcd.quantize, fastquantb); + cpi->mb.quantize_brd = QUANTIZE_INVOKE(&cpi->rtcd.quantize, fastquantb); + } + +#if CONFIG_RUNTIME_CPU_DETECT + cpi->mb.e_mbd.rtcd = &cpi->common.rtcd; +#endif + + if (cpi->sf.iterative_sub_pixel == 1) + { + cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step_iteratively; + } + else if (cpi->sf.quarter_pixel_search) + { + cpi->find_fractional_mv_step = vp8_find_best_sub_pixel_step; + } + else if (cpi->sf.half_pixel_search) + { + cpi->find_fractional_mv_step = vp8_find_best_half_pixel_step; + } + else + { + cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; + } + + if (cpi->sf.optimize_coefficients == 1) + cpi->mb.optimize = 1; + else + cpi->mb.optimize = 0; + + if (cpi->common.full_pixel) + cpi->find_fractional_mv_step = vp8_skip_fractional_mv_step; + +#ifdef SPEEDSTATS + frames_at_speed[cpi->Speed]++; +#endif +} +static void alloc_raw_frame_buffers(VP8_COMP *cpi) +{ + int i, buffers; + + buffers = cpi->oxcf.lag_in_frames; + + if (buffers > MAX_LAG_BUFFERS) + buffers = MAX_LAG_BUFFERS; + + if (buffers < 1) + buffers = 1; + + for (i = 0; i < buffers; i++) + if (vp8_yv12_alloc_frame_buffer(&cpi->src_buffer[i].source_buffer, + cpi->oxcf.Width, cpi->oxcf.Height, + 16)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate lag buffer"); + +#if VP8_TEMPORAL_ALT_REF + + if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer.source_buffer, + cpi->oxcf.Width, cpi->oxcf.Height, 16)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate altref buffer"); + +#endif + + cpi->source_buffer_count = 0; +} +void vp8_alloc_compressor_data(VP8_COMP *cpi) +{ + VP8_COMMON *cm = & cpi->common; + + int width = cm->Width; + int height = cm->Height; + + if (vp8_alloc_frame_buffers(cm, width, height)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate frame buffers"); + + if ((width & 0xf) != 0) + width += 16 - (width & 0xf); + + if ((height & 0xf) != 0) + height += 16 - (height & 0xf); + + + if (vp8_yv12_alloc_frame_buffer(&cpi->last_frame_uf, + width, height, VP8BORDERINPIXELS)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate last frame buffer"); + + if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source, width, height, 16)) + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, + "Failed to allocate scaled source buffer"); + + + if (cpi->tok != 0) + vpx_free(cpi->tok); + + { + unsigned int tokens = cm->mb_rows * cm->mb_cols * 24 * 16; + + CHECK_MEM_ERROR(cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok))); + } + + // Data used for real time vc mode to see if gf needs refreshing + cpi->inter_zz_count = 0; + cpi->gf_bad_count = 0; + cpi->gf_update_recommended = 0; +} + + +// Quant MOD +static const int q_trans[] = +{ + 0, 1, 2, 3, 4, 5, 7, 8, + 9, 10, 12, 13, 15, 17, 18, 19, + 20, 21, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, + 59, 61, 64, 67, 70, 73, 76, 79, + 82, 85, 88, 91, 94, 97, 100, 103, + 106, 109, 112, 115, 118, 121, 124, 127, +}; + +int vp8_reverse_trans(int x) +{ + int i; + + for (i = 0; i < 64; i++) + if (q_trans[i] >= x) + return i; + + return 63; +}; +void vp8_new_frame_rate(VP8_COMP *cpi, double framerate) +{ + cpi->oxcf.frame_rate = framerate; + cpi->output_frame_rate = cpi->oxcf.frame_rate; + cpi->per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / cpi->output_frame_rate); + cpi->av_per_frame_bandwidth = (int)(cpi->oxcf.target_bandwidth / cpi->output_frame_rate); + cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + cpi->rolling_target_bits = cpi->av_per_frame_bandwidth; + cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth; + + cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth; + cpi->long_rolling_actual_bits = cpi->av_per_frame_bandwidth; + cpi->max_gf_interval = (int)(cpi->output_frame_rate / 2) + 2; + + //cpi->max_gf_interval = (int)(cpi->output_frame_rate * 2 / 3) + 1; + //cpi->max_gf_interval = 24; + + if (cpi->max_gf_interval < 12) + cpi->max_gf_interval = 12; + + + // Special conditions when altr ref frame enabled + if (cpi->oxcf.play_alternate) + { + if (cpi->max_gf_interval > cpi->oxcf.lag_in_frames - 1) + cpi->max_gf_interval = cpi->oxcf.lag_in_frames - 1; + } +} + +void vp8_init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + VP8_COMMON *cm = &cpi->common; + + if (!cpi) + return; + + cpi->auto_gold = 1; + cpi->auto_adjust_gold_quantizer = 1; + cpi->goldquantizer = 1; + cpi->goldfreq = 7; + cpi->auto_adjust_key_quantizer = 1; + cpi->keyquantizer = 1; + + cm->version = oxcf->Version; + vp8_setup_version(cm); + + if (oxcf == 0) + { + cpi->pass = 0; + + cpi->auto_worst_q = 0; + cpi->oxcf.best_allowed_q = MINQ; + cpi->oxcf.worst_allowed_q = MAXQ; + + cpi->oxcf.end_usage = USAGE_STREAM_FROM_SERVER; + cpi->oxcf.starting_buffer_level = 4; + cpi->oxcf.optimal_buffer_level = 5; + cpi->oxcf.maximum_buffer_size = 6; + cpi->oxcf.under_shoot_pct = 90; + cpi->oxcf.allow_df = 0; + cpi->oxcf.drop_frames_water_mark = 20; + + cpi->oxcf.allow_spatial_resampling = 0; + cpi->oxcf.resample_down_water_mark = 40; + cpi->oxcf.resample_up_water_mark = 60; + + cpi->oxcf.fixed_q = cpi->interquantizer; + + cpi->filter_type = NORMAL_LOOPFILTER; + + if (cm->simpler_lpf) + cpi->filter_type = SIMPLE_LOOPFILTER; + + cpi->compressor_speed = 1; + cpi->horiz_scale = 0; + cpi->vert_scale = 0; + cpi->oxcf.two_pass_vbrbias = 50; + cpi->oxcf.two_pass_vbrmax_section = 400; + cpi->oxcf.two_pass_vbrmin_section = 0; + + cpi->oxcf.Sharpness = 0; + cpi->oxcf.noise_sensitivity = 0; + } + else + cpi->oxcf = *oxcf; + + + switch (cpi->oxcf.Mode) + { + + case MODE_REALTIME: + cpi->pass = 0; + cpi->compressor_speed = 2; + + if (cpi->oxcf.cpu_used < -16) + { + cpi->oxcf.cpu_used = -16; + } + + if (cpi->oxcf.cpu_used > 16) + cpi->oxcf.cpu_used = 16; + + break; + +#if !(CONFIG_REALTIME_ONLY) + case MODE_GOODQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + + case MODE_BESTQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 0; + break; + + case MODE_FIRSTPASS: + cpi->pass = 1; + cpi->compressor_speed = 1; + break; + case MODE_SECONDPASS: + cpi->pass = 2; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + case MODE_SECONDPASS_BEST: + cpi->pass = 2; + cpi->compressor_speed = 0; + break; +#endif + } + + if (cpi->pass == 0) + cpi->auto_worst_q = 1; + + cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q]; + cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q]; + + if (oxcf->fixed_q >= 0) + { + if (oxcf->worst_allowed_q < 0) + cpi->oxcf.fixed_q = q_trans[0]; + else + cpi->oxcf.fixed_q = q_trans[oxcf->worst_allowed_q]; + + if (oxcf->alt_q < 0) + cpi->oxcf.alt_q = q_trans[0]; + else + cpi->oxcf.alt_q = q_trans[oxcf->alt_q]; + + if (oxcf->key_q < 0) + cpi->oxcf.key_q = q_trans[0]; + else + cpi->oxcf.key_q = q_trans[oxcf->key_q]; + + if (oxcf->gold_q < 0) + cpi->oxcf.gold_q = q_trans[0]; + else + cpi->oxcf.gold_q = q_trans[oxcf->gold_q]; + + } + + cpi->baseline_gf_interval = cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + //cpi->use_golden_frame_only = 0; + //cpi->use_last_frame_only = 0; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + cm->refresh_entropy_probs = 1; + + if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) + cm->multi_token_partition = (TOKEN_PARTITION) cpi->oxcf.token_partitions; + + setup_features(cpi); + + { + int i; + + for (i = 0; i < MAX_MB_SEGMENTS; i++) + cpi->segment_encode_breakout[i] = cpi->oxcf.encode_breakout; + } + + // At the moment the first order values may not be > MAXQ + if (cpi->oxcf.fixed_q > MAXQ) + cpi->oxcf.fixed_q = MAXQ; + + // local file playback mode == really big buffer + if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) + { + cpi->oxcf.starting_buffer_level = 60; + cpi->oxcf.optimal_buffer_level = 60; + cpi->oxcf.maximum_buffer_size = 240; + + } + + + // Convert target bandwidth from Kbit/s to Bit/s + cpi->oxcf.target_bandwidth *= 1000; + cpi->oxcf.starting_buffer_level *= cpi->oxcf.target_bandwidth; + + if (cpi->oxcf.optimal_buffer_level == 0) + cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.optimal_buffer_level *= cpi->oxcf.target_bandwidth; + + if (cpi->oxcf.maximum_buffer_size == 0) + cpi->oxcf.maximum_buffer_size = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.maximum_buffer_size *= cpi->oxcf.target_bandwidth; + + cpi->buffer_level = cpi->oxcf.starting_buffer_level; + cpi->bits_off_target = cpi->oxcf.starting_buffer_level; + + vp8_new_frame_rate(cpi, cpi->oxcf.frame_rate); + cpi->worst_quality = cpi->oxcf.worst_allowed_q; + cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; + cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q; + cpi->best_quality = cpi->oxcf.best_allowed_q; + cpi->active_best_quality = cpi->oxcf.best_allowed_q; + cpi->buffered_mode = (cpi->oxcf.optimal_buffer_level > 0) ? TRUE : FALSE; + + + cpi->total_actual_bits = 0; + cpi->total_target_vs_actual = 0; + + // Only allow dropped frames in buffered mode + cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; + + cm->filter_type = (LOOPFILTERTYPE) cpi->filter_type; + + if (!cm->use_bilinear_mc_filter) + cm->mcomp_filter_type = SIXTAP; + else + cm->mcomp_filter_type = BILINEAR; + + cpi->target_bandwidth = cpi->oxcf.target_bandwidth; + + cm->Width = cpi->oxcf.Width ; + cm->Height = cpi->oxcf.Height ; + + cpi->intra_frame_target = (4 * (cm->Width + cm->Height) / 15) * 1000; // As per VP8 + + cm->horiz_scale = cpi->horiz_scale; + cm->vert_scale = cpi->vert_scale ; + + // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs) + if (cpi->oxcf.Sharpness > 7) + cpi->oxcf.Sharpness = 7; + + cm->sharpness_level = cpi->oxcf.Sharpness; + + if (cm->horiz_scale != NORMAL || cm->vert_scale != NORMAL) + { + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + + // always go to the next whole number + cm->Width = (hs - 1 + cpi->oxcf.Width * hr) / hs; + cm->Height = (vs - 1 + cpi->oxcf.Height * vr) / vs; + } + + if (((cm->Width + 15) & 0xfffffff0) != cm->last_frame.y_width || + ((cm->Height + 15) & 0xfffffff0) != cm->last_frame.y_height || + cm->last_frame.y_width == 0) + { + alloc_raw_frame_buffers(cpi); + vp8_alloc_compressor_data(cpi); + } + + // Clamp KF frame size to quarter of data rate + if (cpi->intra_frame_target > cpi->target_bandwidth >> 2) + cpi->intra_frame_target = cpi->target_bandwidth >> 2; + + if (cpi->oxcf.fixed_q >= 0) + { + cpi->last_q[0] = cpi->oxcf.fixed_q; + cpi->last_q[1] = cpi->oxcf.fixed_q; + } + + cpi->Speed = cpi->oxcf.cpu_used; + + // force to allowlag to 0 if lag_in_frames is 0; + if (cpi->oxcf.lag_in_frames == 0) + { + cpi->oxcf.allow_lag = 0; + } + // Limit on lag buffers as these are not currently dynamically allocated + else if (cpi->oxcf.lag_in_frames > MAX_LAG_BUFFERS) + cpi->oxcf.lag_in_frames = MAX_LAG_BUFFERS; + + // force play_alternate to 0 if allow_lag is 0, lag_in_frames is too small, Mode is real time or one pass compress enabled. + if (cpi->oxcf.allow_lag == 0 || cpi->oxcf.lag_in_frames <= 5 || (cpi->oxcf.Mode < MODE_SECONDPASS)) + { + cpi->oxcf.play_alternate = 0; + cpi->ref_frame_flags = cpi->ref_frame_flags & ~VP8_ALT_FLAG; + } + + // YX Temp + cpi->last_alt_ref_sei = -1; + cpi->is_src_frame_alt_ref = 0; + +#if 0 + // Experimental RD Code + cpi->frame_distortion = 0; + cpi->last_frame_distortion = 0; +#endif + +#if VP8_TEMPORAL_ALT_REF + { + int i; + + cpi->fixed_divide[0] = 0; + + for (i = 1; i < 255; i++) + cpi->fixed_divide[i] = 0x10000 / i; + } +#endif +} + +/* + * This function needs more clean up, i.e. be more tuned torwards + * change_config rather than init_config !!!!!!!!!!!!!!!! + * YX - 5/28/2009 + * + */ + +void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + VP8_COMMON *cm = &cpi->common; + + if (!cpi) + return; + + if (!oxcf) + return; + + if (cm->version != oxcf->Version) + { + cm->version = oxcf->Version; + vp8_setup_version(cm); + } + + cpi->oxcf = *oxcf; + + switch (cpi->oxcf.Mode) + { + + case MODE_REALTIME: + cpi->pass = 0; + cpi->compressor_speed = 2; + + if (cpi->oxcf.cpu_used < -16) + { + cpi->oxcf.cpu_used = -16; + } + + if (cpi->oxcf.cpu_used > 16) + cpi->oxcf.cpu_used = 16; + + break; + +#if !(CONFIG_REALTIME_ONLY) + case MODE_GOODQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + + case MODE_BESTQUALITY: + cpi->pass = 0; + cpi->compressor_speed = 0; + break; + + case MODE_FIRSTPASS: + cpi->pass = 1; + cpi->compressor_speed = 1; + break; + case MODE_SECONDPASS: + cpi->pass = 2; + cpi->compressor_speed = 1; + + if (cpi->oxcf.cpu_used < -5) + { + cpi->oxcf.cpu_used = -5; + } + + if (cpi->oxcf.cpu_used > 5) + cpi->oxcf.cpu_used = 5; + + break; + case MODE_SECONDPASS_BEST: + cpi->pass = 2; + cpi->compressor_speed = 0; + break; +#endif + } + + if (cpi->pass == 0) + cpi->auto_worst_q = 1; + + cpi->oxcf.worst_allowed_q = q_trans[oxcf->worst_allowed_q]; + cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q]; + + if (oxcf->fixed_q >= 0) + { + if (oxcf->worst_allowed_q < 0) + cpi->oxcf.fixed_q = q_trans[0]; + else + cpi->oxcf.fixed_q = q_trans[oxcf->worst_allowed_q]; + + if (oxcf->alt_q < 0) + cpi->oxcf.alt_q = q_trans[0]; + else + cpi->oxcf.alt_q = q_trans[oxcf->alt_q]; + + if (oxcf->key_q < 0) + cpi->oxcf.key_q = q_trans[0]; + else + cpi->oxcf.key_q = q_trans[oxcf->key_q]; + + if (oxcf->gold_q < 0) + cpi->oxcf.gold_q = q_trans[0]; + else + cpi->oxcf.gold_q = q_trans[oxcf->gold_q]; + + } + + cpi->baseline_gf_interval = cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; + + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + //cpi->use_golden_frame_only = 0; + //cpi->use_last_frame_only = 0; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + cm->refresh_entropy_probs = 1; + + if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) + cm->multi_token_partition = (TOKEN_PARTITION) cpi->oxcf.token_partitions; + + setup_features(cpi); + + { + int i; + + for (i = 0; i < MAX_MB_SEGMENTS; i++) + cpi->segment_encode_breakout[i] = cpi->oxcf.encode_breakout; + } + + // At the moment the first order values may not be > MAXQ + if (cpi->oxcf.fixed_q > MAXQ) + cpi->oxcf.fixed_q = MAXQ; + + // local file playback mode == really big buffer + if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) + { + cpi->oxcf.starting_buffer_level = 60; + cpi->oxcf.optimal_buffer_level = 60; + cpi->oxcf.maximum_buffer_size = 240; + + } + + // Convert target bandwidth from Kbit/s to Bit/s + cpi->oxcf.target_bandwidth *= 1000; + + cpi->oxcf.starting_buffer_level *= cpi->oxcf.target_bandwidth; + + if (cpi->oxcf.optimal_buffer_level == 0) + cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.optimal_buffer_level *= cpi->oxcf.target_bandwidth; + + if (cpi->oxcf.maximum_buffer_size == 0) + cpi->oxcf.maximum_buffer_size = cpi->oxcf.target_bandwidth / 8; + else + cpi->oxcf.maximum_buffer_size *= cpi->oxcf.target_bandwidth; + + cpi->buffer_level = cpi->oxcf.starting_buffer_level; + cpi->bits_off_target = cpi->oxcf.starting_buffer_level; + + vp8_new_frame_rate(cpi, cpi->oxcf.frame_rate); + cpi->worst_quality = cpi->oxcf.worst_allowed_q; + cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; + cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q; + cpi->best_quality = cpi->oxcf.best_allowed_q; + cpi->active_best_quality = cpi->oxcf.best_allowed_q; + cpi->buffered_mode = (cpi->oxcf.optimal_buffer_level > 0) ? TRUE : FALSE; + + + cpi->total_actual_bits = 0; + cpi->total_target_vs_actual = 0; + + // Only allow dropped frames in buffered mode + cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; + + cm->filter_type = (LOOPFILTERTYPE) cpi->filter_type; + + if (!cm->use_bilinear_mc_filter) + cm->mcomp_filter_type = SIXTAP; + else + cm->mcomp_filter_type = BILINEAR; + + cpi->target_bandwidth = cpi->oxcf.target_bandwidth; + + cm->Width = cpi->oxcf.Width ; + cm->Height = cpi->oxcf.Height ; + + cm->horiz_scale = cpi->horiz_scale; + cm->vert_scale = cpi->vert_scale ; + + cpi->intra_frame_target = (4 * (cm->Width + cm->Height) / 15) * 1000; // As per VP8 + + // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs) + if (cpi->oxcf.Sharpness > 7) + cpi->oxcf.Sharpness = 7; + + cm->sharpness_level = cpi->oxcf.Sharpness; + + if (cm->horiz_scale != NORMAL || cm->vert_scale != NORMAL) + { + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + + // always go to the next whole number + cm->Width = (hs - 1 + cpi->oxcf.Width * hr) / hs; + cm->Height = (vs - 1 + cpi->oxcf.Height * vr) / vs; + } + + if (((cm->Width + 15) & 0xfffffff0) != cm->last_frame.y_width || + ((cm->Height + 15) & 0xfffffff0) != cm->last_frame.y_height || + cm->last_frame.y_width == 0) + { + alloc_raw_frame_buffers(cpi); + vp8_alloc_compressor_data(cpi); + } + + // Clamp KF frame size to quarter of data rate + if (cpi->intra_frame_target > cpi->target_bandwidth >> 2) + cpi->intra_frame_target = cpi->target_bandwidth >> 2; + + if (cpi->oxcf.fixed_q >= 0) + { + cpi->last_q[0] = cpi->oxcf.fixed_q; + cpi->last_q[1] = cpi->oxcf.fixed_q; + } + + cpi->Speed = cpi->oxcf.cpu_used; + + // force to allowlag to 0 if lag_in_frames is 0; + if (cpi->oxcf.lag_in_frames == 0) + { + cpi->oxcf.allow_lag = 0; + } + // Limit on lag buffers as these are not currently dynamically allocated + else if (cpi->oxcf.lag_in_frames > MAX_LAG_BUFFERS) + cpi->oxcf.lag_in_frames = MAX_LAG_BUFFERS; + + // force play_alternate to 0 if allow_lag is 0, lag_in_frames is too small, Mode is real time or one pass compress enabled. + if (cpi->oxcf.allow_lag == 0 || cpi->oxcf.lag_in_frames <= 5 || (cpi->oxcf.Mode < MODE_SECONDPASS)) + { + cpi->oxcf.play_alternate = 0; + cpi->ref_frame_flags = cpi->ref_frame_flags & ~VP8_ALT_FLAG; + } + + // YX Temp + cpi->last_alt_ref_sei = -1; + cpi->is_src_frame_alt_ref = 0; + +#if 0 + // Experimental RD Code + cpi->frame_distortion = 0; + cpi->last_frame_distortion = 0; +#endif + +} + +#define M_LOG2_E 0.693147180559945309417 +#define log2f(x) (log (x) / (float) M_LOG2_E) +static void cal_mvsadcosts(int *mvsadcost[2]) +{ + int i = 1; + + mvsadcost [0] [0] = 300; + mvsadcost [1] [0] = 300; + + do + { + double z = 256 * (2 * (log2f(2 * i) + .6)); + mvsadcost [0][i] = (int) z; + mvsadcost [1][i] = (int) z; + mvsadcost [0][-i] = (int) z; + mvsadcost [1][-i] = (int) z; + } + while (++i <= mv_max); +} + +VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) +{ + int i; + volatile union + { + VP8_COMP *cpi; + VP8_PTR ptr; + } ctx; + + VP8_COMP *cpi; + VP8_COMMON *cm; + + cpi = ctx.cpi = vpx_memalign(32, sizeof(VP8_COMP)); + // Check that the CPI instance is valid + if (!cpi) + return 0; + + cm = &cpi->common; + + vpx_memset(cpi, 0, sizeof(VP8_COMP)); + + if (setjmp(cm->error.jmp)) + { + VP8_PTR ptr = ctx.ptr; + + ctx.cpi->common.error.setjmp = 0; + vp8_remove_compressor(&ptr); + return 0; + } + + cpi->common.error.setjmp = 1; + + CHECK_MEM_ERROR(cpi->rdtok, vpx_calloc(256 * 3 / 2, sizeof(TOKENEXTRA))); + CHECK_MEM_ERROR(cpi->mb.ss, vpx_calloc(sizeof(search_site), (MAX_MVSEARCH_STEPS * 8) + 1)); + + vp8_cmachine_specific_config(cpi); + vp8_create_common(&cpi->common); + + vp8_init_config((VP8_PTR)cpi, oxcf); + + memcpy(cpi->base_skip_false_prob, vp8cx_base_skip_false_prob, sizeof(vp8cx_base_skip_false_prob)); + cpi->common.current_video_frame = 0; + cpi->kf_overspend_bits = 0; + cpi->kf_bitrate_adjustment = 0; + cpi->frames_till_gf_update_due = 0; + cpi->gf_overspend_bits = 0; + cpi->non_gf_bitrate_adjustment = 0; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + cpi->prob_intra_coded = 63; + + // Prime the recent reference frame useage counters. + // Hereafter they will be maintained as a sort of moving average + cpi->recent_ref_frame_usage[INTRA_FRAME] = 1; + cpi->recent_ref_frame_usage[LAST_FRAME] = 1; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] = 1; + cpi->recent_ref_frame_usage[ALTREF_FRAME] = 1; + + // Set reference frame sign bias for ALTREF frame to 1 (for now) + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 1; + + cpi->gf_decay_rate = 0; + cpi->baseline_gf_interval = DEFAULT_GF_INTERVAL; + + cpi->gold_is_last = 0 ; + cpi->alt_is_last = 0 ; + cpi->gold_is_alt = 0 ; + + + + // Create the encoder segmentation map and set all entries to 0 + CHECK_MEM_ERROR(cpi->segmentation_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + CHECK_MEM_ERROR(cpi->active_map, vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1)); + vpx_memset(cpi->active_map , 1, (cpi->common.mb_rows * cpi->common.mb_cols)); + cpi->active_map_enabled = 0; + + // Create the first pass motion map structure and set to 0 + CHECK_MEM_ERROR(cpi->fp_motion_map, vpx_calloc(cpi->common.MBs, 1)); + +#if 0 + // Experimental code for lagged and one pass + // Initialise one_pass GF frames stats + // Update stats used for GF selection + if (cpi->pass == 0) + { + cpi->one_pass_frame_index = 0; + + for (i = 0; i < MAX_LAG_BUFFERS; i++) + { + cpi->one_pass_frame_stats[i].frames_so_far = 0; + cpi->one_pass_frame_stats[i].frame_intra_error = 0.0; + cpi->one_pass_frame_stats[i].frame_coded_error = 0.0; + cpi->one_pass_frame_stats[i].frame_pcnt_inter = 0.0; + cpi->one_pass_frame_stats[i].frame_pcnt_motion = 0.0; + cpi->one_pass_frame_stats[i].frame_mvr = 0.0; + cpi->one_pass_frame_stats[i].frame_mvr_abs = 0.0; + cpi->one_pass_frame_stats[i].frame_mvc = 0.0; + cpi->one_pass_frame_stats[i].frame_mvc_abs = 0.0; + } + } +#endif + + // Should we use the cyclic refresh method. + // Currently this is tied to error resilliant mode + cpi->cyclic_refresh_mode_enabled = cpi->oxcf.error_resilient_mode; + cpi->cyclic_refresh_mode_max_mbs_perframe = (cpi->common.mb_rows * cpi->common.mb_cols) / 40; + cpi->cyclic_refresh_mode_index = 0; + cpi->cyclic_refresh_q = 32; + + if (cpi->cyclic_refresh_mode_enabled) + { + CHECK_MEM_ERROR(cpi->cyclic_refresh_map, vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1)); + } + else + cpi->cyclic_refresh_map = (signed char *) NULL; + + // Test function for segmentation + //segmentation_test_function((VP8_PTR) cpi); + + // Loop filter mode / ref deltas test function + //mode_ref_lf_test_function(cpi); + +#ifdef ENTROPY_STATS + init_context_counters(); +#endif + + +#ifdef INTRARDOPT + cpi->intra_rd_opt = 1; + +#endif + + cpi->frames_since_key = 8; // Give a sensible default for the first frame. + cpi->key_frame_frequency = cpi->oxcf.key_freq; + + cpi->source_alt_ref_pending = FALSE; + cpi->source_alt_ref_active = FALSE; + cpi->common.refresh_alt_ref_frame = 0; + + cpi->b_calculate_psnr = CONFIG_PSNR; +#if CONFIG_PSNR + cpi->b_calculate_ssimg = 0; + + cpi->count = 0; + cpi->bytes = 0; + + if (cpi->b_calculate_psnr) + { + cpi->total_sq_error = 0.0; + cpi->total_sq_error2 = 0.0; + cpi->total_y = 0.0; + cpi->total_u = 0.0; + cpi->total_v = 0.0; + cpi->total = 0.0; + cpi->totalp_y = 0.0; + cpi->totalp_u = 0.0; + cpi->totalp_v = 0.0; + cpi->totalp = 0.0; + cpi->tot_recode_hits = 0; + cpi->summed_quality = 0; + cpi->summed_weights = 0; + } + + if (cpi->b_calculate_ssimg) + { + cpi->total_ssimg_y = 0; + cpi->total_ssimg_u = 0; + cpi->total_ssimg_v = 0; + cpi->total_ssimg_all = 0; + } + +#ifndef LLONG_MAX +#define LLONG_MAX 9223372036854775807LL +#endif + cpi->first_time_stamp_ever = LLONG_MAX; + +#endif + + cpi->frames_till_gf_update_due = 0; + cpi->key_frame_count = 1; + cpi->tot_key_frame_bits = 0; + + cpi->ni_av_qi = cpi->oxcf.worst_allowed_q; + cpi->ni_tot_qi = 0; + cpi->ni_frames = 0; + cpi->total_byte_count = 0; + + cpi->drop_frame = 0; + cpi->drop_count = 0; + cpi->max_drop_count = 0; + cpi->max_consec_dropped_frames = 4; + + cpi->rate_correction_factor = 1.0; + cpi->key_frame_rate_correction_factor = 1.0; + cpi->gf_rate_correction_factor = 1.0; + cpi->est_max_qcorrection_factor = 1.0; + + cpi->mb.mvcost[0] = &cpi->mb.mvcosts[0][mv_max+1]; + cpi->mb.mvcost[1] = &cpi->mb.mvcosts[1][mv_max+1]; + cpi->mb.mvsadcost[0] = &cpi->mb.mvsadcosts[0][mv_max+1]; + cpi->mb.mvsadcost[1] = &cpi->mb.mvsadcosts[1][mv_max+1]; + + cal_mvsadcosts(cpi->mb.mvsadcost); + + for (i = 0; i < KEY_FRAME_CONTEXT; i++) + { + cpi->prior_key_frame_size[i] = cpi->intra_frame_target; + cpi->prior_key_frame_distance[i] = (int)cpi->output_frame_rate; + } + + cpi->check_freq[0] = 15; + cpi->check_freq[1] = 15; + +#ifdef OUTPUT_YUV_SRC + yuv_file = fopen("bd.yuv", "ab"); +#endif + +#if 0 + framepsnr = fopen("framepsnr.stt", "a"); + kf_list = fopen("kf_list.stt", "w"); +#endif + + cpi->output_pkt_list = oxcf->output_pkt_list; + +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 1) + { + vp8_init_first_pass(cpi); + } + else if (cpi->pass == 2) + { + cpi->stats_in = oxcf->two_pass_stats_in.buf; + cpi->stats_in_end = cpi->stats_in + + oxcf->two_pass_stats_in.sz / sizeof(FIRSTPASS_STATS) + - 1; + vp8_init_second_pass(cpi); + } + +#endif + + if (cpi->compressor_speed == 2) + { + cpi->cpu_freq = 0; //vp8_get_processor_freq(); + cpi->avg_encode_time = 0; + cpi->avg_pick_mode_time = 0; + } + + vp8_set_speed_features(cpi); + + // Set starting values of RD threshold multipliers (128 = *1) + for (i = 0; i < MAX_MODES; i++) + { + cpi->rd_thresh_mult[i] = 128; + } + +#ifdef ENTROPY_STATS + init_mv_ref_counts(); +#endif + + vp8cx_create_encoder_threads(cpi); + + cpi->fn_ptr.sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16); + cpi->fn_ptr.vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x16); + cpi->fn_ptr.svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar16x16); + cpi->fn_ptr.sdx3f = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16x3); + cpi->fn_ptr.sdx4df = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x16x4d); + +#if !(CONFIG_REALTIME_ONLY) + cpi->full_search_sad = SEARCH_INVOKE(&cpi->rtcd.search, full_search); +#endif + cpi->diamond_search_sad = SEARCH_INVOKE(&cpi->rtcd.search, diamond_search); + + cpi->ready_for_new_frame = 1; + + cpi->source_encode_index = 0; + + // make sure frame 1 is okay + cpi->error_bins[0] = cpi->common.MBs; + + //vp8cx_init_quantizer() is first called here. Add check in vp8cx_frame_init_quantizer() so that vp8cx_init_quantizer is only called later + //when needed. This will avoid unnecessary calls of vp8cx_init_quantizer() for every frame. + vp8cx_init_quantizer(cpi); + { + vp8_init_loop_filter(cm); + cm->last_frame_type = KEY_FRAME; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + } + cpi->common.error.setjmp = 0; + return (VP8_PTR) cpi; + +} + + +void vp8_remove_compressor(VP8_PTR *ptr) +{ + VP8_COMP *cpi = (VP8_COMP *)(*ptr); + + if (!cpi) + return; + + if (cpi && (cpi->common.current_video_frame > 0)) + { +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 2) + { + vp8_end_second_pass(cpi); + } + +#endif + +#ifdef ENTROPY_STATS + print_context_counters(); + print_tree_update_probs(); + print_mode_context(); +#endif + +#if CONFIG_PSNR + + if (cpi->pass != 1) + { + FILE *f = fopen("opsnr.stt", "a"); + double time_encoded = (cpi->source_end_time_stamp - cpi->first_time_stamp_ever) / 10000000.000; + double total_encode_time = (cpi->time_receive_data + cpi->time_compress_data) / 1000.000; + double dr = (double)cpi->bytes * (double) 8 / (double)1000 / time_encoded; + + if (cpi->b_calculate_psnr) + { + double samples = 3.0 / 2 * cpi->count * cpi->common.last_frame.y_width * cpi->common.last_frame.y_height; + double total_psnr = vp8_mse2psnr(samples, 255.0, cpi->total_sq_error); + double total_psnr2 = vp8_mse2psnr(samples, 255.0, cpi->total_sq_error2); + double total_ssim = 100 * pow(cpi->summed_quality / cpi->summed_weights, 8.0); + + fprintf(f, "Bitrate\AVGPsnr\tGLBPsnr\tAVPsnrP\tGLPsnrP\tVPXSSIM\t Time(us)\n"); + fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f %8.0f\n", + dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim, + total_encode_time); + } + + if (cpi->b_calculate_ssimg) + { + fprintf(f, "BitRate\tSSIM_Y\tSSIM_U\tSSIM_V\tSSIM_A\t Time(us)\n"); + fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr, + cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count, + cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time); + } + + fclose(f); +#if 0 + f = fopen("qskip.stt", "a"); + fprintf(f, "minq:%d -maxq:%d skipture:skipfalse = %d:%d\n", cpi->oxcf.best_allowed_q, cpi->oxcf.worst_allowed_q, skiptruecount, skipfalsecount); + fclose(f); +#endif + + } + +#endif + + +#ifdef SPEEDSTATS + + if (cpi->compressor_speed == 2) + { + int i; + FILE *f = fopen("cxspeed.stt", "a"); + cnt_pm /= cpi->common.MBs; + + for (i = 0; i < 16; i++) + fprintf(f, "%5d", frames_at_speed[i]); + + fprintf(f, "\n"); + //fprintf(f, "%10d PM %10d %10d %10d EF %10d %10d %10d\n", cpi->Speed, cpi->avg_pick_mode_time, (tot_pm/cnt_pm), cnt_pm, cpi->avg_encode_time, 0, 0); + fclose(f); + } + +#endif + + +#ifdef MODE_STATS + { + extern int count_mb_seg[4]; + FILE *f = fopen("modes.stt", "a"); + double dr = (double)cpi->oxcf.frame_rate * (double)bytes * (double)8 / (double)count / (double)1000 ; + fprintf(f, "intra_mode in Intra Frames:\n"); + fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d\n", y_modes[0], y_modes[1], y_modes[2], y_modes[3], y_modes[4]); + fprintf(f, "UV:%8d, %8d, %8d, %8d\n", uv_modes[0], uv_modes[1], uv_modes[2], uv_modes[3]); + fprintf(f, "B: "); + { + int i; + + for (i = 0; i < 10; i++) + fprintf(f, "%8d, ", b_modes[i]); + + fprintf(f, "\n"); + + } + + fprintf(f, "Modes in Inter Frames:\n"); + fprintf(f, "Y: %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d, %8d\n", + inter_y_modes[0], inter_y_modes[1], inter_y_modes[2], inter_y_modes[3], inter_y_modes[4], + inter_y_modes[5], inter_y_modes[6], inter_y_modes[7], inter_y_modes[8], inter_y_modes[9]); + fprintf(f, "UV:%8d, %8d, %8d, %8d\n", inter_uv_modes[0], inter_uv_modes[1], inter_uv_modes[2], inter_uv_modes[3]); + fprintf(f, "B: "); + { + int i; + + for (i = 0; i < 15; i++) + fprintf(f, "%8d, ", inter_b_modes[i]); + + fprintf(f, "\n"); + + } + fprintf(f, "P:%8d, %8d, %8d, %8d\n", count_mb_seg[0], count_mb_seg[1], count_mb_seg[2], count_mb_seg[3]); + fprintf(f, "PB:%8d, %8d, %8d, %8d\n", inter_b_modes[LEFT4X4], inter_b_modes[ABOVE4X4], inter_b_modes[ZERO4X4], inter_b_modes[NEW4X4]); + + + + fclose(f); + } +#endif + +#ifdef ENTROPY_STATS + { + int i, j, k; + FILE *fmode = fopen("modecontext.c", "w"); + + fprintf(fmode, "\n#include \"entropymode.h\"\n\n"); + fprintf(fmode, "const unsigned int vp8_kf_default_bmode_counts "); + fprintf(fmode, "[VP8_BINTRAMODES] [VP8_BINTRAMODES] [VP8_BINTRAMODES] =\n{\n"); + + for (i = 0; i < 10; i++) + { + + fprintf(fmode, " { //Above Mode : %d\n", i); + + for (j = 0; j < 10; j++) + { + + fprintf(fmode, " {"); + + for (k = 0; k < 10; k++) + { + if (!intra_mode_stats[i][j][k]) + fprintf(fmode, " %5d, ", 1); + else + fprintf(fmode, " %5d, ", intra_mode_stats[i][j][k]); + } + + fprintf(fmode, "}, // left_mode %d\n", j); + + } + + fprintf(fmode, " },\n"); + + } + + fprintf(fmode, "};\n"); + } +#endif + + +#if defined(SECTIONBITS_OUTPUT) + + if (0) + { + int i; + FILE *f = fopen("tokenbits.stt", "a"); + + for (i = 0; i < 28; i++) + fprintf(f, "%8d", (int)(Sectionbits[i] / 256)); + + fprintf(f, "\n"); + fclose(f); + } + +#endif + +#if 0 + { + printf("\n_pick_loop_filter_level:%d\n", cpi->time_pick_lpf / 1000); + printf("\n_frames recive_data encod_mb_row compress_frame Total\n"); + printf("%6d %10ld %10ld %10ld %10ld\n", cpi->common.current_video_frame, cpi->time_receive_data / 1000, cpi->time_encode_mb_row / 1000, cpi->time_compress_data / 1000, (cpi->time_receive_data + cpi->time_compress_data) / 1000); + } +#endif + + } + + vp8cx_remove_encoder_threads(cpi); + + vp8_dealloc_compressor_data(cpi); + vpx_free(cpi->mb.ss); + vpx_free(cpi->tok); + vpx_free(cpi->rdtok); + vpx_free(cpi->cyclic_refresh_map); + + vp8_remove_common(&cpi->common); + vpx_free(cpi); + *ptr = 0; + +#ifdef OUTPUT_YUV_SRC + fclose(yuv_file); +#endif + +#if 0 + + if (keyfile) + fclose(keyfile); + + if (framepsnr) + fclose(framepsnr); + + if (kf_list) + fclose(kf_list); + +#endif + +} + + +static uint64_t calc_plane_error(unsigned char *orig, int orig_stride, + unsigned char *recon, int recon_stride, + unsigned int cols, unsigned int rows, + vp8_variance_rtcd_vtable_t *rtcd) +{ + unsigned int row, col; + uint64_t total_sse = 0; + int diff; + + for (row = 0; row + 16 <= rows; row += 16) + { + for (col = 0; col + 16 <= cols; col += 16) + { + unsigned int sse; + + VARIANCE_INVOKE(rtcd, mse16x16)(orig + col, orig_stride, + recon + col, recon_stride, + &sse); + total_sse += sse; + } + + /* Handle odd-sized width */ + if (col < cols) + { + unsigned int border_row, border_col; + unsigned char *border_orig = orig; + unsigned char *border_recon = recon; + + for (border_row = 0; border_row < 16; border_row++) + { + for (border_col = col; border_col < cols; border_col++) + { + diff = border_orig[border_col] - border_recon[border_col]; + total_sse += diff * diff; + } + + border_orig += orig_stride; + border_recon += recon_stride; + } + } + + orig += orig_stride * 16; + recon += recon_stride * 16; + } + + /* Handle odd-sized height */ + for (; row < rows; row++) + { + for (col = 0; col < cols; col++) + { + diff = orig[col] - recon[col]; + total_sse += diff * diff; + } + + orig += orig_stride; + recon += recon_stride; + } + + return total_sse; +} + + +static void generate_psnr_packet(VP8_COMP *cpi) +{ + YV12_BUFFER_CONFIG *orig = cpi->Source; + YV12_BUFFER_CONFIG *recon = cpi->common.frame_to_show; + struct vpx_codec_cx_pkt pkt; + uint64_t sse; + int i; + unsigned int width = cpi->common.Width; + unsigned int height = cpi->common.Height; + + pkt.kind = VPX_CODEC_PSNR_PKT; + sse = calc_plane_error(orig->y_buffer, orig->y_stride, + recon->y_buffer, recon->y_stride, + width, height, + IF_RTCD(&cpi->rtcd.variance)); + pkt.data.psnr.sse[0] = sse; + pkt.data.psnr.sse[1] = sse; + pkt.data.psnr.samples[0] = width * height; + pkt.data.psnr.samples[1] = width * height; + + width = (width + 1) / 2; + height = (height + 1) / 2; + + sse = calc_plane_error(orig->u_buffer, orig->uv_stride, + recon->u_buffer, recon->uv_stride, + width, height, + IF_RTCD(&cpi->rtcd.variance)); + pkt.data.psnr.sse[0] += sse; + pkt.data.psnr.sse[2] = sse; + pkt.data.psnr.samples[0] += width * height; + pkt.data.psnr.samples[2] = width * height; + + sse = calc_plane_error(orig->v_buffer, orig->uv_stride, + recon->v_buffer, recon->uv_stride, + width, height, + IF_RTCD(&cpi->rtcd.variance)); + pkt.data.psnr.sse[0] += sse; + pkt.data.psnr.sse[3] = sse; + pkt.data.psnr.samples[0] += width * height; + pkt.data.psnr.samples[3] = width * height; + + for (i = 0; i < 4; i++) + pkt.data.psnr.psnr[i] = vp8_mse2psnr(pkt.data.psnr.samples[i], 255.0, + pkt.data.psnr.sse[i]); + + vpx_codec_pkt_list_add(cpi->output_pkt_list, &pkt); +} + + +int vp8_use_as_reference(VP8_PTR ptr, int ref_frame_flags) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + if (ref_frame_flags > 7) + return -1 ; + + cpi->ref_frame_flags = ref_frame_flags; + return 0; +} +int vp8_update_reference(VP8_PTR ptr, int ref_frame_flags) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + + if (ref_frame_flags > 7) + return -1 ; + + cpi->common.refresh_golden_frame = 0; + cpi->common.refresh_alt_ref_frame = 0; + cpi->common.refresh_last_frame = 0; + + if (ref_frame_flags & VP8_LAST_FLAG) + cpi->common.refresh_last_frame = 1; + + if (ref_frame_flags & VP8_GOLD_FLAG) + cpi->common.refresh_golden_frame = 1; + + if (ref_frame_flags & VP8_ALT_FLAG) + cpi->common.refresh_alt_ref_frame = 1; + + return 0; +} + +int vp8_get_reference(VP8_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + VP8_COMMON *cm = &cpi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(&cm->last_frame, sd); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, sd); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, sd); + + else + return -1; + + return 0; +} +int vp8_set_reference(VP8_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) +{ + VP8_COMP *cpi = (VP8_COMP *)(ptr); + VP8_COMMON *cm = &cpi->common; + + if (ref_frame_flag == VP8_LAST_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->last_frame); + + else if (ref_frame_flag == VP8_GOLD_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->golden_frame); + + else if (ref_frame_flag == VP8_ALT_FLAG) + vp8_yv12_copy_frame_ptr(sd, &cm->alt_ref_frame); + + else + return -1; + + return 0; +} +int vp8_update_entropy(VP8_PTR comp, int update) +{ + VP8_COMP *cpi = (VP8_COMP *) comp; + VP8_COMMON *cm = &cpi->common; + cm->refresh_entropy_probs = update; + + return 0; +} + +void vp8_write_yuv_frame(const char *name, YV12_BUFFER_CONFIG *s) +{ + FILE *yuv_file = fopen(name, "ab"); + unsigned char *src = s->y_buffer; + int h = s->y_height; + + do + { + fwrite(src, s->y_width, 1, yuv_file); + src += s->y_stride; + } + while (--h); + + src = s->u_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + src = s->v_buffer; + h = s->uv_height; + + do + { + fwrite(src, s->uv_width, 1, yuv_file); + src += s->uv_stride; + } + while (--h); + + fclose(yuv_file); +} + +static void scale_and_extend_source(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // are we resizing the image + if (cm->horiz_scale != 0 || cm->vert_scale != 0) + { +#if CONFIG_SPATIAL_RESAMPLING + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + int tmp_height; + + if (cm->vert_scale == 3) + tmp_height = 9; + else + tmp_height = 11; + + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + + vp8_scale_frame(sd, &cpi->scaled_source, cm->temp_scale_frame.y_buffer, + tmp_height, hs, hr, vs, vr, 0); + + cpi->Source = &cpi->scaled_source; +#endif + } + // we may need to copy to a buffer so we can extend the image... + else if (cm->Width != cm->last_frame.y_width || + cm->Height != cm->last_frame.y_height) + { + //vp8_yv12_copy_frame_ptr(sd, &cpi->scaled_source); +#if HAVE_ARMV7 + vp8_yv12_copy_src_frame_func_neon(sd, &cpi->scaled_source); +#else + vp8_yv12_copy_frame_ptr(sd, &cpi->scaled_source); +#endif + + cpi->Source = &cpi->scaled_source; + } + + vp8_extend_to_multiple_of16(cpi->Source, cm->Width, cm->Height); + +} +static void resize_key_frame(VP8_COMP *cpi) +{ +#if CONFIG_SPATIAL_RESAMPLING + VP8_COMMON *cm = &cpi->common; + + // Do we need to apply resampling for one pass cbr. + // In one pass this is more limited than in two pass cbr + // The test and any change is only made one per key frame sequence + if (cpi->oxcf.allow_spatial_resampling && (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) + { + int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs); + int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs); + int new_width, new_height; + + // If we are below the resample DOWN watermark then scale down a notch. + if (cpi->buffer_level < (cpi->oxcf.resample_down_water_mark * cpi->oxcf.optimal_buffer_level / 100)) + { + cm->horiz_scale = (cm->horiz_scale < ONETWO) ? cm->horiz_scale + 1 : ONETWO; + cm->vert_scale = (cm->vert_scale < ONETWO) ? cm->vert_scale + 1 : ONETWO; + } + // Should we now start scaling back up + else if (cpi->buffer_level > (cpi->oxcf.resample_up_water_mark * cpi->oxcf.optimal_buffer_level / 100)) + { + cm->horiz_scale = (cm->horiz_scale > NORMAL) ? cm->horiz_scale - 1 : NORMAL; + cm->vert_scale = (cm->vert_scale > NORMAL) ? cm->vert_scale - 1 : NORMAL; + } + + // Get the new hieght and width + Scale2Ratio(cm->horiz_scale, &hr, &hs); + Scale2Ratio(cm->vert_scale, &vr, &vs); + new_width = ((hs - 1) + (cpi->oxcf.Width * hr)) / hs; + new_height = ((vs - 1) + (cpi->oxcf.Height * vr)) / vs; + + // If the image size has changed we need to reallocate the buffers + // and resample the source image + if ((cm->Width != new_width) || (cm->Height != new_height)) + { + cm->Width = new_width; + cm->Height = new_height; + vp8_alloc_compressor_data(cpi); + scale_and_extend_source(cpi->un_scaled_source, cpi); + } + } + +#endif +} +// return of 0 means drop frame +static int pick_frame_size(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // First Frame is a special case + if (cm->current_video_frame == 0) + { +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 2) + vp8_calc_auto_iframe_target_size(cpi); + + // 1 Pass there is no information on which to base size so use bandwidth per second * fixed fraction + else +#endif + cpi->this_frame_target = cpi->oxcf.target_bandwidth / 2; + + // in error resilient mode the first frame is bigger since it likely contains + // all the static background + if (cpi->oxcf.error_resilient_mode == 1 || (cpi->compressor_speed == 2)) + { + cpi->this_frame_target *= 3; // 5; + } + + // Key frame from VFW/auto-keyframe/first frame + cm->frame_type = KEY_FRAME; + + } + // Auto key frames (Only two pass will enter here) + else if (cm->frame_type == KEY_FRAME) + { + vp8_calc_auto_iframe_target_size(cpi); + } + // Forced key frames (by interval or an external signal) + else if ((cm->frame_flags & FRAMEFLAGS_KEY) || + (cpi->oxcf.auto_key && (cpi->frames_since_key % cpi->key_frame_frequency == 0))) + { + // Key frame from VFW/auto-keyframe/first frame + cm->frame_type = KEY_FRAME; + + resize_key_frame(cpi); + + // Compute target frame size + if (cpi->pass != 2) + vp8_calc_iframe_target_size(cpi); + } + else + { + // INTER frame: compute target frame size + cm->frame_type = INTER_FRAME; + vp8_calc_pframe_target_size(cpi); + + // Check if we're dropping the frame: + if (cpi->drop_frame) + { + cpi->drop_frame = FALSE; + cpi->drop_count++; + return 0; + } + } + + // Note target_size in bits * 256 per MB + cpi->target_bits_per_mb = (cpi->this_frame_target * 256) / cpi->common.MBs; + + return 1; +} +static void set_quantizer(VP8_COMP *cpi, int Q) +{ + VP8_COMMON *cm = &cpi->common; + MACROBLOCKD *mbd = &cpi->mb.e_mbd; + + cm->base_qindex = Q; + + cm->y1dc_delta_q = 0; + cm->y2dc_delta_q = 0; + cm->y2ac_delta_q = 0; + cm->uvdc_delta_q = 0; + cm->uvac_delta_q = 0; + + // Set Segment specific quatizers + mbd->segment_feature_data[MB_LVL_ALT_Q][0] = cpi->segment_feature_data[MB_LVL_ALT_Q][0]; + mbd->segment_feature_data[MB_LVL_ALT_Q][1] = cpi->segment_feature_data[MB_LVL_ALT_Q][1]; + mbd->segment_feature_data[MB_LVL_ALT_Q][2] = cpi->segment_feature_data[MB_LVL_ALT_Q][2]; + mbd->segment_feature_data[MB_LVL_ALT_Q][3] = cpi->segment_feature_data[MB_LVL_ALT_Q][3]; +} + +static void update_alt_ref_frame_and_stats(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // Update the golden frame buffer + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); + + // Select an interval before next GF or altref + if (!cpi->auto_gold) + cpi->frames_till_gf_update_due = cpi->goldfreq; + + if ((cpi->pass != 2) && cpi->frames_till_gf_update_due) + { + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + // Set the bits per frame that we should try and recover in subsequent inter frames + // to account for the extra GF spend... note that his does not apply for GF updates + // that occur coincident with a key frame as the extra cost of key frames is dealt + // with elsewhere. + + cpi->gf_overspend_bits += cpi->projected_frame_size; + cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; + } + + // Update data structure that monitors level of reference to last GF + vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cm->gf_active_count = cm->mb_rows * cm->mb_cols; + // this frame refreshes means next frames don't unless specified by user + + cpi->common.frames_since_golden = 0; + + // Clear the alternate reference update pending flag. + cpi->source_alt_ref_pending = FALSE; + + // Set the alternate refernce frame active flag + cpi->source_alt_ref_active = TRUE; + + +} +static void update_golden_frame_and_stats(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + // Update the Golden frame reconstruction buffer if signalled and the GF usage counts. + if (cm->refresh_golden_frame) + { + // Update the golden frame buffer + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); + + // Select an interval before next GF + if (!cpi->auto_gold) + cpi->frames_till_gf_update_due = cpi->goldfreq; + + if ((cpi->pass != 2) && (cpi->frames_till_gf_update_due > 0)) + { + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + // Set the bits per frame that we should try and recover in subsequent inter frames + // to account for the extra GF spend... note that his does not apply for GF updates + // that occur coincident with a key frame as the extra cost of key frames is dealt + // with elsewhere. + if ((cm->frame_type != KEY_FRAME) && !cpi->source_alt_ref_active) + { + // Calcluate GF bits to be recovered + // Projected size - av frame bits available for inter frames for clip as a whole + cpi->gf_overspend_bits += (cpi->projected_frame_size - cpi->inter_frame_target); + } + + cpi->non_gf_bitrate_adjustment = cpi->gf_overspend_bits / cpi->frames_till_gf_update_due; + + } + + // Update data structure that monitors level of reference to last GF + vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); + cm->gf_active_count = cm->mb_rows * cm->mb_cols; + + // this frame refreshes means next frames don't unless specified by user + cm->refresh_golden_frame = 0; + cpi->common.frames_since_golden = 0; + + //if ( cm->frame_type == KEY_FRAME ) + //{ + cpi->recent_ref_frame_usage[INTRA_FRAME] = 1; + cpi->recent_ref_frame_usage[LAST_FRAME] = 1; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] = 1; + cpi->recent_ref_frame_usage[ALTREF_FRAME] = 1; + //} + //else + //{ + // // Carry a potrtion of count over to begining of next gf sequence + // cpi->recent_ref_frame_usage[INTRA_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[LAST_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[GOLDEN_FRAME] >>= 5; + // cpi->recent_ref_frame_usage[ALTREF_FRAME] >>= 5; + //} + + // ******** Fixed Q test code only ************ + // If we are going to use the ALT reference for the next group of frames set a flag to say so. + if (cpi->oxcf.fixed_q >= 0 && + cpi->oxcf.play_alternate && !cpi->common.refresh_alt_ref_frame) + { + cpi->source_alt_ref_pending = TRUE; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + } + + if (!cpi->source_alt_ref_pending) + cpi->source_alt_ref_active = FALSE; + + // Decrement count down till next gf + if (cpi->frames_till_gf_update_due > 0) + cpi->frames_till_gf_update_due--; + + } + else if (!cpi->common.refresh_alt_ref_frame) + { + // Decrement count down till next gf + if (cpi->frames_till_gf_update_due > 0) + cpi->frames_till_gf_update_due--; + + if (cpi->common.frames_till_alt_ref_frame) + cpi->common.frames_till_alt_ref_frame --; + + cpi->common.frames_since_golden ++; + + if (cpi->common.frames_since_golden > 1) + { + cpi->recent_ref_frame_usage[INTRA_FRAME] += cpi->count_mb_ref_frame_usage[INTRA_FRAME]; + cpi->recent_ref_frame_usage[LAST_FRAME] += cpi->count_mb_ref_frame_usage[LAST_FRAME]; + cpi->recent_ref_frame_usage[GOLDEN_FRAME] += cpi->count_mb_ref_frame_usage[GOLDEN_FRAME]; + cpi->recent_ref_frame_usage[ALTREF_FRAME] += cpi->count_mb_ref_frame_usage[ALTREF_FRAME]; + } + } +} + +// This function updates the reference frame probability estimates that +// will be used during mode selection +static void update_rd_ref_frame_probs(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + +#if 0 + const int *const rfct = cpi->recent_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + if (cm->frame_type == KEY_FRAME) + { + cpi->prob_intra_coded = 255; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + else if (!(rf_intra + rf_inter)) + { + // This is a trap in case this function is called with cpi->recent_ref_frame_usage[] blank. + cpi->prob_intra_coded = 63; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + else + { + cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); + + if (cpi->prob_intra_coded < 1) + cpi->prob_intra_coded = 1; + + if ((cm->frames_since_golden > 0) || cpi->source_alt_ref_active) + { + cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (cpi->prob_last_coded < 1) + cpi->prob_last_coded = 1; + + cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (cpi->prob_gf_coded < 1) + cpi->prob_gf_coded = 1; + } + } + +#else + const int *const rfct = cpi->count_mb_ref_frame_usage; + const int rf_intra = rfct[INTRA_FRAME]; + const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]; + + if (cm->frame_type == KEY_FRAME) + { + cpi->prob_intra_coded = 255; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + else if (!(rf_intra + rf_inter)) + { + // This is a trap in case this function is called with cpi->recent_ref_frame_usage[] blank. + cpi->prob_intra_coded = 63; + cpi->prob_last_coded = 128; + cpi->prob_gf_coded = 128; + } + else + { + cpi->prob_intra_coded = (rf_intra * 255) / (rf_intra + rf_inter); + + if (cpi->prob_intra_coded < 1) + cpi->prob_intra_coded = 1; + + cpi->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128; + + if (cpi->prob_last_coded < 1) + cpi->prob_last_coded = 1; + + cpi->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) + ? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128; + + if (cpi->prob_gf_coded < 1) + cpi->prob_gf_coded = 1; + } + + // update reference frame costs since we can do better than what we got last frame. + + if (cpi->common.refresh_alt_ref_frame) + { + cpi->prob_intra_coded += 40; + cpi->prob_last_coded = 200; + cpi->prob_gf_coded = 1; + } + else if (cpi->common.frames_since_golden == 0) + { + cpi->prob_last_coded = 214; + cpi->prob_gf_coded = 1; + } + else if (cpi->common.frames_since_golden == 1) + { + cpi->prob_last_coded = 192; + cpi->prob_gf_coded = 220; + } + else if (cpi->source_alt_ref_active) + { + //int dist = cpi->common.frames_till_alt_ref_frame + cpi->common.frames_since_golden; + cpi->prob_gf_coded -= 20; + + if (cpi->prob_gf_coded < 10) + cpi->prob_gf_coded = 10; + } + +#endif +} + + +// 1 = key, 0 = inter +static int decide_key_frame(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int code_key_frame = FALSE; + + cpi->kf_boost = 0; + + if (cpi->Speed > 11) + return FALSE; + + // Clear down mmx registers + vp8_clear_system_state(); //__asm emms; + + if ((cpi->compressor_speed == 2) && (cpi->Speed >= 5) && (cpi->sf.RD == 0)) + { + double change = 1.0 * abs((int)(cpi->intra_error - cpi->last_intra_error)) / (1 + cpi->last_intra_error); + double change2 = 1.0 * abs((int)(cpi->prediction_error - cpi->last_prediction_error)) / (1 + cpi->last_prediction_error); + double minerror = cm->MBs * 256; + +#if 0 + + if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 + && cpi->prediction_error > minerror + && (change > .25 || change2 > .25)) + { + FILE *f = fopen("intra_inter.stt", "a"); + + if (cpi->prediction_error <= 0) + cpi->prediction_error = 1; + + fprintf(f, "%d %d %d %d %14.4f\n", + cm->current_video_frame, + (int) cpi->prediction_error, + (int) cpi->intra_error, + (int)((10 * cpi->intra_error) / cpi->prediction_error), + change); + + fclose(f); + } + +#endif + + cpi->last_intra_error = cpi->intra_error; + cpi->last_prediction_error = cpi->prediction_error; + + if (10 * cpi->intra_error / (1 + cpi->prediction_error) < 15 + && cpi->prediction_error > minerror + && (change > .25 || change2 > .25)) + { + /*(change > 1.4 || change < .75)&& cpi->this_frame_percent_intra > cpi->last_frame_percent_intra + 3*/ + return TRUE; + } + + return FALSE; + + } + + // If the following are true we might as well code a key frame + if (((cpi->this_frame_percent_intra == 100) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra + 2))) || + ((cpi->this_frame_percent_intra > 95) && + (cpi->this_frame_percent_intra >= (cpi->last_frame_percent_intra + 5)))) + { + code_key_frame = TRUE; + } + // in addition if the following are true and this is not a golden frame then code a key frame + // Note that on golden frames there often seems to be a pop in intra useage anyway hence this + // restriction is designed to prevent spurious key frames. The Intra pop needs to be investigated. + else if (((cpi->this_frame_percent_intra > 60) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra * 2))) || + ((cpi->this_frame_percent_intra > 75) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra * 3 / 2))) || + ((cpi->this_frame_percent_intra > 90) && + (cpi->this_frame_percent_intra > (cpi->last_frame_percent_intra + 10)))) + { + if (!cm->refresh_golden_frame) + code_key_frame = TRUE; + } + + return code_key_frame; + +} + +#if !(CONFIG_REALTIME_ONLY) +static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) +{ + (void) size; + (void) dest; + (void) frame_flags; + set_quantizer(cpi, 26); + + scale_and_extend_source(cpi->un_scaled_source, cpi); + vp8_first_pass(cpi); +} +#endif + +#if 0 +void write_cx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) +{ + + // write the frame + FILE *yframe; + int i; + char filename[255]; + + sprintf(filename, "cx\\y%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->y_height; i++) + fwrite(frame->y_buffer + i * frame->y_stride, frame->y_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "cx\\u%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->u_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + + fclose(yframe); + sprintf(filename, "cx\\v%04d.raw", this_frame); + yframe = fopen(filename, "wb"); + + for (i = 0; i < frame->uv_height; i++) + fwrite(frame->v_buffer + i * frame->uv_stride, frame->uv_width, 1, yframe); + + fclose(yframe); +} +#endif +// return of 0 means drop frame + +#if VP8_TEMPORAL_ALT_REF +static void vp8cx_temp_blur1_c +( + unsigned char **frames, + int frame_count, + unsigned char *src, + unsigned char *dst, + int width, + int stride, + int height, + int strength, + int *fixed_divide, + unsigned char *motion_map_ptr, + unsigned char block_size +) +{ + int byte = 0; // Buffer offset for the current pixel value being filtered + int frame = 0; + int modifier = 0; + int i, j, k; + int block_ofset; + int Cols, Rows; + unsigned char Shift = (block_size == 16) ? 4 : 3; + + Cols = width / block_size; + Rows = height / block_size; + + for (i = 0; i < height; i++) + { + block_ofset = (i >> Shift) * Cols; + + for (j = 0; j < Cols; j ++) + { + if (motion_map_ptr[block_ofset] > 2) + { + vpx_memcpy(&dst[byte], &src[byte], block_size); + byte += block_size; + } + else + { + for (k = 0; k < block_size; k++) + { + int accumulator = 0; + int count = 0; + int src_byte = src[byte]; + + for (frame = 0; frame < frame_count; frame++) + { + // get current frame pixel value + int pixel_value = frames[frame][byte]; // int pixel_value = *frameptr; + + modifier = src_byte; // modifier = s[byte]; + modifier -= pixel_value; + modifier *= modifier; + modifier >>= strength; + modifier *= 3; + + if (modifier > 16) + modifier = 16; + + modifier = 16 - modifier; + + accumulator += modifier * pixel_value; + + count += modifier; + } + + accumulator += (count >> 1); + accumulator *= fixed_divide[count]; // accumulator *= ppi->fixed_divide[count]; + accumulator >>= 16; + + dst[byte] = accumulator; // d[byte] = accumulator; + + // move to next pixel + byte++; + } + } + + block_ofset++; + } + + // Step byte on over the UMV border to the start of the next line + byte += stride - width; + } +} + +static void vp8cx_temp_filter_c +( + VP8_COMP *cpi +) +{ + YV12_BUFFER_CONFIG *temp_source_buffer; + int *fixed_divide = cpi->fixed_divide; + + int frame = 0; + int max_frames = 11; + + int num_frames_backward = 0; + int num_frames_forward = 0; + int frames_to_blur_backward = 0; + int frames_to_blur_forward = 0; + int frames_to_blur = 0; + int start_frame = 0; + + int strength = cpi->oxcf.arnr_strength; + + int blur_type = cpi->oxcf.arnr_type; + + int new_max_frames = cpi->oxcf.arnr_max_frames; + + if (new_max_frames > 0) + max_frames = new_max_frames; + + num_frames_backward = cpi->last_alt_ref_sei - cpi->source_encode_index; + + if (num_frames_backward < 0) + num_frames_backward += cpi->oxcf.lag_in_frames; + + num_frames_forward = cpi->oxcf.lag_in_frames - (num_frames_backward + 1); + + switch (blur_type) + { + case 1: + ///////////////////////////////////////// + // Backward Blur + + frames_to_blur_backward = num_frames_backward; + + if (frames_to_blur_backward >= max_frames) + frames_to_blur_backward = max_frames - 1; + + frames_to_blur = frames_to_blur_backward + 1; + break; + + case 2: + ///////////////////////////////////////// + // Forward Blur + + frames_to_blur_forward = num_frames_forward; + + if (frames_to_blur_forward >= max_frames) + frames_to_blur_forward = max_frames - 1; + + frames_to_blur = frames_to_blur_forward + 1; + break; + + case 3: + ///////////////////////////////////////// + // Center Blur + frames_to_blur_forward = num_frames_forward; + frames_to_blur_backward = num_frames_backward; + + if (frames_to_blur_forward > frames_to_blur_backward) + frames_to_blur_forward = frames_to_blur_backward; + + if (frames_to_blur_backward > frames_to_blur_forward) + frames_to_blur_backward = frames_to_blur_forward; + + if (frames_to_blur_forward > (max_frames / 2)) + frames_to_blur_forward = (max_frames / 2); + + if (frames_to_blur_backward > (max_frames / 2)) + frames_to_blur_backward = (max_frames / 2); + + frames_to_blur = frames_to_blur_backward + frames_to_blur_forward + 1; + break; + + default: + ///////////////////////////////////////// + // At most 4 frames forward Blur + frames_to_blur_forward = 4; + frames_to_blur_backward = num_frames_backward; + + if (max_frames > 5) + { + if ((frames_to_blur_backward + frames_to_blur_forward) >= max_frames) + { + frames_to_blur_backward = max_frames - frames_to_blur_forward - 1; + } + } + else + { + frames_to_blur_forward = max_frames - 1; + frames_to_blur_backward = 0; + } + + frames_to_blur = frames_to_blur_backward + frames_to_blur_forward + 1; + break; + } + + start_frame = (cpi->last_alt_ref_sei + frames_to_blur_forward) % cpi->oxcf.lag_in_frames; + +#ifdef DEBUGFWG + // DEBUG FWG + printf("max:%d FBCK:%d FFWD:%d ftb:%d ftbbck:%d ftbfwd:%d sei:%d lasei:%d start:%d" + , max_frames + , num_frames_backward + , num_frames_forward + , frames_to_blur + , frames_to_blur_backward + , frames_to_blur_forward + , cpi->source_encode_index + , cpi->last_alt_ref_sei + , start_frame); +#endif + + for (frame = 0; frame < frames_to_blur; frame++) + { + int which_buffer = start_frame - frame; + + if (which_buffer < 0) + which_buffer += cpi->oxcf.lag_in_frames; + + cpi->frames[frame] = cpi->src_buffer[which_buffer].source_buffer.y_buffer; + } + + temp_source_buffer = &cpi->src_buffer[cpi->last_alt_ref_sei].source_buffer; + + // Blur Y + vp8cx_temp_blur1_c( + cpi->frames, + frames_to_blur, + temp_source_buffer->y_buffer, // cpi->Source->y_buffer, + cpi->alt_ref_buffer.source_buffer.y_buffer, // cpi->Source->y_buffer, + temp_source_buffer->y_width, + temp_source_buffer->y_stride, + temp_source_buffer->y_height, + //temp_source_buffer->y_height * temp_source_buffer->y_stride, + strength, + fixed_divide, + cpi->fp_motion_map, 16); + + for (frame = 0; frame < frames_to_blur; frame++) + { + int which_buffer = cpi->last_alt_ref_sei - frame; + + if (which_buffer < 0) + which_buffer += cpi->oxcf.lag_in_frames; + + cpi->frames[frame] = cpi->src_buffer[which_buffer].source_buffer.u_buffer; + } + + // Blur U + vp8cx_temp_blur1_c( + cpi->frames, + frames_to_blur, + temp_source_buffer->u_buffer, + cpi->alt_ref_buffer.source_buffer.u_buffer, // cpi->Source->u_buffer, + temp_source_buffer->uv_width, + temp_source_buffer->uv_stride, + temp_source_buffer->uv_height, + //temp_source_buffer->uv_height * temp_source_buffer->uv_stride, + strength, + fixed_divide, + cpi->fp_motion_map, 8); + + for (frame = 0; frame < frames_to_blur; frame++) + { + int which_buffer = cpi->last_alt_ref_sei - frame; + + if (which_buffer < 0) + which_buffer += cpi->oxcf.lag_in_frames; + + cpi->frames[frame] = cpi->src_buffer[which_buffer].source_buffer.v_buffer; + } + + // Blur V + vp8cx_temp_blur1_c( + cpi->frames, + frames_to_blur, + temp_source_buffer->v_buffer, + cpi->alt_ref_buffer.source_buffer.v_buffer, // cpi->Source->v_buffer, + temp_source_buffer->uv_width, + temp_source_buffer->uv_stride, + //temp_source_buffer->uv_height * temp_source_buffer->uv_stride, + temp_source_buffer->uv_height, + strength, + fixed_divide, + cpi->fp_motion_map, 8); +} +#endif + + +static void encode_frame_to_data_rate(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) +{ + int Q; + int frame_over_shoot_limit; + int frame_under_shoot_limit; + + int Loop = FALSE; + int loop_count; + int this_q; + int last_zbin_oq; + + int q_low; + int q_high; + int zbin_oq_high; + int zbin_oq_low = 0; + int top_index; + int bottom_index; + VP8_COMMON *cm = &cpi->common; + int active_worst_qchanged = FALSE; + + int overshoot_seen = FALSE; + int undershoot_seen = FALSE; + int drop_mark = cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100; + int drop_mark75 = drop_mark * 2 / 3; + int drop_mark50 = drop_mark / 4; + int drop_mark25 = drop_mark / 8; + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); + + // Test code for segmentation of gf/arf (0,0) + //segmentation_test_function((VP8_PTR) cpi); + + // For an alt ref frame in 2 pass we skip the call to the second pass function that sets the target bandwidth +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 2) + { + if (cpi->common.refresh_alt_ref_frame) + { + cpi->per_frame_bandwidth = cpi->gf_bits; // Per frame bit target for the alt ref frame + cpi->target_bandwidth = cpi->gf_bits * cpi->output_frame_rate; // per second target bitrate + } + } + else +#endif + cpi->per_frame_bandwidth = (int)(cpi->target_bandwidth / cpi->output_frame_rate); + + // Default turn off buffer to buffer copying + cm->copy_buffer_to_gf = 0; + cm->copy_buffer_to_arf = 0; + + // Clear zbin over-quant value and mode boost values. + cpi->zbin_over_quant = 0; + cpi->zbin_mode_boost = 0; + + // Enable mode based tweaking of the zbin + cpi->zbin_mode_boost_enabled = TRUE; + + // Current default encoder behaviour for the altref sign bias + if (cpi->source_alt_ref_active) + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 1; + else + cpi->common.ref_frame_sign_bias[ALTREF_FRAME] = 0; + + // Check to see if a key frame is signalled + // For two pass with auto key frame enabled cm->frame_type may already be set, but not for one pass. + if ((cm->current_video_frame == 0) || + (cm->frame_flags & FRAMEFLAGS_KEY) || + (cpi->oxcf.auto_key && (cpi->frames_since_key % cpi->key_frame_frequency == 0))) + { + // Key frame from VFW/auto-keyframe/first frame + cm->frame_type = KEY_FRAME; + } + + // Set default state for segment and mode based loop filter update flags + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + + // Set various flags etc to special state if it is a key frame + if (cm->frame_type == KEY_FRAME) + { + int i; + + // If segmentation is enabled force a map update for key frames + if (cpi->mb.e_mbd.segmentation_enabled) + { + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; + } + + // If mode or reference frame based loop filter deltas are enabled then force an update for key frames. + if (cpi->mb.e_mbd.mode_ref_lf_delta_enabled) + { + cpi->mb.e_mbd.mode_ref_lf_delta_update = 1; + } + + // The alternate reference frame cannot be active for a key frame + cpi->source_alt_ref_active = FALSE; + + // Reset the RD threshold multipliers to default of * 1 (128) + for (i = 0; i < MAX_MODES; i++) + { + cpi->rd_thresh_mult[i] = 128; + } + } + + // Test code for segmentation + //if ( (cm->frame_type == KEY_FRAME) || ((cm->current_video_frame % 2) == 0)) + //if ( (cm->current_video_frame % 2) == 0 ) + // enable_segmentation((VP8_PTR)cpi); + //else + // disable_segmentation((VP8_PTR)cpi); + +#if 0 + // Experimental code for lagged compress and one pass + // Initialise one_pass GF frames stats + // Update stats used for GF selection + //if ( cpi->pass == 0 ) + { + cpi->one_pass_frame_index = cm->current_video_frame % MAX_LAG_BUFFERS; + + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frames_so_far = 0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_intra_error = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_coded_error = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_inter = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_pcnt_motion = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvr_abs = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc = 0.0; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index ].frame_mvc_abs = 0.0; + } +#endif + + update_rd_ref_frame_probs(cpi); + + if (cpi->drop_frames_allowed) + { + // The reset to decimation 0 is only done here for one pass. + // Once it is set two pass leaves decimation on till the next kf. + if ((cpi->buffer_level > drop_mark) && (cpi->decimation_factor > 0)) + cpi->decimation_factor --; + + if (cpi->buffer_level > drop_mark75 && cpi->decimation_factor > 0) + cpi->decimation_factor = 1; + + else if (cpi->buffer_level < drop_mark25 && (cpi->decimation_factor == 2 || cpi->decimation_factor == 3)) + { + cpi->decimation_factor = 3; + } + else if (cpi->buffer_level < drop_mark50 && (cpi->decimation_factor == 1 || cpi->decimation_factor == 2)) + { + cpi->decimation_factor = 2; + } + else if (cpi->buffer_level < drop_mark75 && (cpi->decimation_factor == 0 || cpi->decimation_factor == 1)) + { + cpi->decimation_factor = 1; + } + + //vpx_log("Encoder: Decimation Factor: %d \n",cpi->decimation_factor); + } + + // The following decimates the frame rate according to a regular pattern (i.e. to 1/2 or 2/3 frame rate) + // This can be used to help prevent buffer under-run in CBR mode. Alternatively it might be desirable in + // some situations to drop frame rate but throw more bits at each frame. + // + // Note that dropping a key frame can be problematic if spatial resampling is also active + if (cpi->decimation_factor > 0) + { + switch (cpi->decimation_factor) + { + case 1: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 3 / 2; + break; + case 2: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; + break; + case 3: + cpi->per_frame_bandwidth = cpi->per_frame_bandwidth * 5 / 4; + break; + } + + // Note that we should not throw out a key frame (especially when spatial resampling is enabled). + if ((cm->frame_type == KEY_FRAME)) // && cpi->oxcf.allow_spatial_resampling ) + { + cpi->decimation_count = cpi->decimation_factor; + } + else if (cpi->decimation_count > 0) + { + cpi->decimation_count --; + cpi->bits_off_target += cpi->av_per_frame_bandwidth; + cm->current_video_frame++; + cpi->frames_since_key++; + +#if CONFIG_PSNR + cpi->count ++; +#endif + + cpi->buffer_level = cpi->bits_off_target; + + return; + } + else + cpi->decimation_count = cpi->decimation_factor; + } + + // Decide how big to make the frame + if (!pick_frame_size(cpi)) + { + cm->current_video_frame++; + cpi->frames_since_key++; + return; + } + + // Reduce active_worst_allowed_q for CBR if our buffer is getting too full. + // This has a knock on effect on active best quality as well. + // For CBR if the buffer reaches its maximum level then we can no longer + // save up bits for later frames so we might as well use them up + // on the current frame. + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level >= cpi->oxcf.optimal_buffer_level) && cpi->buffered_mode) + { + int Adjustment = cpi->active_worst_quality / 4; // Max adjustment is 1/4 + + if (Adjustment) + { + int buff_lvl_step; + int tmp_lvl = cpi->buffer_level; + + if (cpi->buffer_level < cpi->oxcf.maximum_buffer_size) + { + buff_lvl_step = (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level) / Adjustment; + + if (buff_lvl_step) + { + Adjustment = (cpi->buffer_level - cpi->oxcf.optimal_buffer_level) / buff_lvl_step; + cpi->active_worst_quality -= Adjustment; + } + } + else + { + cpi->active_worst_quality -= Adjustment; + } + } + } + + // Set an active best quality and if necessary active worst quality + if (cpi->pass == 2 || (cm->current_video_frame > 150)) + { + //if ( (cm->frame_type == KEY_FRAME) || cm->refresh_golden_frame ) + int Q; + int i; + int bpm_target; + + Q = cpi->active_worst_quality; + + if ((cm->frame_type == KEY_FRAME) || cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame) + { + vp8_clear_system_state(); + + if (cm->frame_type != KEY_FRAME) + { + // Where a gf overlays an existing arf then allow active max Q to drift to highest allowed value. + //if ( cpi->common.refresh_golden_frame && cpi->source_alt_ref_active ) + //cpi->active_worst_quality = cpi->worst_quality; + + if (cpi->avg_frame_qindex < cpi->active_worst_quality) + Q = cpi->avg_frame_qindex; + + if (cpi->section_is_low_motion) + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * ((Q * 3 / 2) + 128)) / 64; + else if (cpi->section_is_fast_motion) + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * (Q + 128)) / 64; + else + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * ((Q * 5 / 4) + 128)) / 64; + } + // KEY FRAMES + else + { + if (cpi->section_is_low_motion) + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * (Q + 240)) / 64; // Approx 2.5 to 4.5 where Q has the range 0-127 + else + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * (Q + 160)) / 64; + } + + for (i = Q; i > 0; i--) + { + if (bpm_target <= vp8_bits_per_mb[cm->frame_type][i]) + break; + } + + cpi->active_best_quality = i; + + // this entire section could be replaced by a look up table +#if 0 + { + int Q, best_q[128]; + + for (Q = 0; Q < 128; Q++) + { + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * (Q + 160)) / 64; // Approx 2.5 to 4.5 where Q has the range 0-127 + + for (i = Q; i > 0; i--) + { + if (bpm_target <= vp8_bits_per_mb[cm->frame_type][i]) + break; + } + + best_q[Q] = i; + } + + Q += 0; + } +#endif + + } + else + { + vp8_clear_system_state(); + + //bpm_target = (vp8_bits_per_mb[cm->frame_type][Q]*(Q+128))/64; // Approx 2 to 4 where Q has the range 0-127 + bpm_target = (vp8_bits_per_mb[cm->frame_type][Q] * (Q + 192)) / 128; // Approx * 1.5 to 2.5 where Q has range 0-127 + + for (i = Q; i > 0; i--) + { + if (bpm_target <= vp8_bits_per_mb[cm->frame_type][i]) + break; + } + + cpi->active_best_quality = i; + } + + // If CBR and the buffer is as full then it is reasonable to allow higher quality on the frames + // to prevent bits just going to waste. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Note that the use of >= here elliminates the risk of a devide by 0 error in the else if clause + if (cpi->buffer_level >= cpi->oxcf.maximum_buffer_size) + cpi->active_best_quality = cpi->best_quality; + + else if (cpi->buffer_level > cpi->oxcf.optimal_buffer_level) + { + int Fraction = ((cpi->buffer_level - cpi->oxcf.optimal_buffer_level) * 128) / (cpi->oxcf.maximum_buffer_size - cpi->oxcf.optimal_buffer_level); + int min_qadjustment = ((cpi->active_best_quality - cpi->best_quality) * Fraction) / 128; + + cpi->active_best_quality -= min_qadjustment; + } + + } + } + + // Clip the active best and worst quality values to limits + if (cpi->active_worst_quality > cpi->worst_quality) + cpi->active_worst_quality = cpi->worst_quality; + + if (cpi->active_best_quality < cpi->best_quality) + cpi->active_best_quality = cpi->best_quality; + else if (cpi->active_best_quality > cpi->active_worst_quality) + cpi->active_best_quality = cpi->active_worst_quality; + + // Determine initial Q to try + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + last_zbin_oq = cpi->zbin_over_quant; + + // Set highest allowed value for Zbin over quant + if (cm->frame_type == KEY_FRAME) + zbin_oq_high = 0; //ZBIN_OQ_MAX/16 + else if (cm->refresh_alt_ref_frame || (cm->refresh_golden_frame && !cpi->source_alt_ref_active)) + zbin_oq_high = 16; + else + zbin_oq_high = ZBIN_OQ_MAX; + + // Setup background Q adjustment for error resilliant mode + if (cpi->cyclic_refresh_mode_enabled) + cyclic_background_refresh(cpi, Q, 0); + + vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); + + // Limit Q range for the adaptive loop (Values not clipped to range 20-60 as in VP8). + bottom_index = cpi->active_best_quality; + top_index = cpi->active_worst_quality; + + vp8_save_coding_context(cpi); + + loop_count = 0; + + q_low = cpi->best_quality; + q_high = cpi->worst_quality; + + + scale_and_extend_source(cpi->un_scaled_source, cpi); +#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC + + if (cpi->oxcf.noise_sensitivity > 0) + { + unsigned char *src; + int l = 0; + + switch (cpi->oxcf.noise_sensitivity) + { + case 1: + l = 20; + break; + case 2: + l = 40; + break; + case 3: + l = 60; + break; + case 4: + l = 80; + break; + case 5: + l = 100; + break; + case 6: + l = 150; + break; + } + + + if (cm->frame_type == KEY_FRAME) + { + vp8_de_noise(cpi->Source, cpi->Source, l , 1, 0, RTCD(postproc)); + cpi->ppi.frame = 0; + } + else + { + vp8_de_noise(cpi->Source, cpi->Source, l , 1, 0, RTCD(postproc)); + + src = cpi->Source->y_buffer; + + if (cpi->Source->y_stride < 0) + { + src += cpi->Source->y_stride * (cpi->Source->y_height - 1); + } + + //temp_filter(&cpi->ppi,src,src, + // cm->last_frame.y_width * cm->last_frame.y_height, + // cpi->oxcf.noise_sensitivity); + } + } + +#endif + +#ifdef OUTPUT_YUV_SRC + vp8_write_yuv_frame(cpi->Source); +#endif + + do + { + vp8_clear_system_state(); //__asm emms; + + /* + if(cpi->is_src_frame_alt_ref) + Q = 127; + */ + + set_quantizer(cpi, Q); + this_q = Q; + + // setup skip prob for costing in mode/mv decision + if (cpi->common.mb_no_coeff_skip) + { + cpi->prob_skip_false = cpi->base_skip_false_prob[Q]; + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->common.refresh_alt_ref_frame) + { + if (cpi->last_skip_false_probs[2] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[2]; + + /* + if(cpi->last_skip_false_probs[2]!=0 && abs(Q- cpi->last_skip_probs_q[2])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[2]; + else if (cpi->last_skip_false_probs[2]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[2] + cpi->prob_skip_false ) / 2; + */ + } + else if (cpi->common.refresh_golden_frame) + { + if (cpi->last_skip_false_probs[1] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[1]; + + /* + if(cpi->last_skip_false_probs[1]!=0 && abs(Q- cpi->last_skip_probs_q[1])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[1]; + else if (cpi->last_skip_false_probs[1]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[1] + cpi->prob_skip_false ) / 2; + */ + } + else + { + if (cpi->last_skip_false_probs[0] != 0) + cpi->prob_skip_false = cpi->last_skip_false_probs[0]; + + /* + if(cpi->last_skip_false_probs[0]!=0 && abs(Q- cpi->last_skip_probs_q[0])<=16 ) + cpi->prob_skip_false = cpi->last_skip_false_probs[0]; + else if(cpi->last_skip_false_probs[0]!=0) + cpi->prob_skip_false = (cpi->last_skip_false_probs[0] + cpi->prob_skip_false ) / 2; + */ + } + + //as this is for cost estimate, let's make sure it does not go extreme eitehr way + if (cpi->prob_skip_false < 5) + cpi->prob_skip_false = 5; + + if (cpi->prob_skip_false > 250) + cpi->prob_skip_false = 250; + + if (cpi->is_src_frame_alt_ref) + cpi->prob_skip_false = 1; + + + } + +#if 0 + + if (cpi->pass != 1) + { + FILE *f = fopen("skip.stt", "a"); + fprintf(f, "%d, %d, %4d ", cpi->common.refresh_golden_frame, cpi->common.refresh_alt_ref_frame, cpi->prob_skip_false); + fclose(f); + } + +#endif + + } + + if (cm->frame_type == KEY_FRAME) + vp8_setup_key_frame(cpi); + + // transform / motion compensation build reconstruction frame + + vp8_encode_frame(cpi); + cpi->projected_frame_size -= vp8_estimate_entropy_savings(cpi); + cpi->projected_frame_size = (cpi->projected_frame_size > 0) ? cpi->projected_frame_size : 0; + + vp8_clear_system_state(); //__asm emms; + + // Test to see if the stats generated for this frame indicate that we should have coded a key frame + // (assuming that we didn't)! + if (cpi->pass != 2 && cpi->oxcf.auto_key && cm->frame_type != KEY_FRAME) + { + if (decide_key_frame(cpi)) + { + vp8_calc_auto_iframe_target_size(cpi); + + // Reset all our sizing numbers and recode + cm->frame_type = KEY_FRAME; + + // Clear the Alt reference frame active flag when we have a key frame + cpi->source_alt_ref_active = FALSE; + + // If segmentation is enabled force a map update for key frames + if (cpi->mb.e_mbd.segmentation_enabled) + { + cpi->mb.e_mbd.update_mb_segmentation_map = 1; + cpi->mb.e_mbd.update_mb_segmentation_data = 1; + } + + // If mode or reference frame based loop filter deltas are enabled then force an update for key frames. + if (cpi->mb.e_mbd.mode_ref_lf_delta_enabled) + { + cpi->mb.e_mbd.mode_ref_lf_delta_update = 1; + } + + vp8_restore_coding_context(cpi); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + q_low = cpi->best_quality; + q_high = cpi->worst_quality; + + vp8_compute_frame_size_bounds(cpi, &frame_under_shoot_limit, &frame_over_shoot_limit); + + // Limit Q range for the adaptive loop (Values not clipped to range 20-60 as in VP8). + bottom_index = cpi->active_best_quality; + top_index = cpi->active_worst_quality; + + + loop_count++; + Loop = TRUE; + + resize_key_frame(cpi); + continue; + } + } + + vp8_clear_system_state(); + + if (frame_over_shoot_limit == 0) + frame_over_shoot_limit = 1; + + // Are we are overshooting and up against the limit of active max Q. + if (((cpi->pass != 2) || (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) && + (Q == cpi->active_worst_quality) && + (cpi->active_worst_quality < cpi->worst_quality) && + (cpi->projected_frame_size > frame_over_shoot_limit)) + { + int over_size_percent = ((cpi->projected_frame_size - frame_over_shoot_limit) * 100) / frame_over_shoot_limit; + + // If so is there any scope for relaxing it + while ((cpi->active_worst_quality < cpi->worst_quality) && (over_size_percent > 0)) + { + cpi->active_worst_quality++; + top_index = cpi->active_worst_quality; + over_size_percent = (int)(over_size_percent * 0.96); // Assume 1 qstep = about 4% on frame size. + } + + // If we have updated the active max Q do not call vp8_update_rate_correction_factors() this loop. + active_worst_qchanged = TRUE; + } + else + active_worst_qchanged = FALSE; + +#if !(CONFIG_REALTIME_ONLY) + + // Is the projected frame size out of range and are we allowed to attempt to recode. + if (((cpi->sf.recode_loop == 1) || + ((cpi->sf.recode_loop == 2) && (cm->refresh_golden_frame || (cm->frame_type == KEY_FRAME)))) && + (((cpi->projected_frame_size > frame_over_shoot_limit) && (Q < top_index)) || + //((cpi->projected_frame_size > frame_over_shoot_limit ) && (Q == top_index) && (cpi->zbin_over_quant < ZBIN_OQ_MAX)) || + ((cpi->projected_frame_size < frame_under_shoot_limit) && (Q > bottom_index))) + ) + { + int last_q = Q; + int Retries = 0; + + // Frame size out of permitted range: + // Update correction factor & compute new Q to try... + if (cpi->projected_frame_size > frame_over_shoot_limit) + { + //if ( cpi->zbin_over_quant == 0 ) + q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value + + if (cpi->zbin_over_quant > 0) // If we are using over quant do the same for zbin_oq_low + zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; + + //if ( undershoot_seen || (Q == MAXQ) ) + if (undershoot_seen) + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 1); + + Q = (q_high + q_low + 1) / 2; + + // Adjust cpi->zbin_over_quant (only allowed when Q is max) + if (Q < MAXQ) + cpi->zbin_over_quant = 0; + else + { + zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; + cpi->zbin_over_quant = (zbin_oq_high + zbin_oq_low) / 2; + } + } + else + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 0); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + while (((Q < q_low) || (cpi->zbin_over_quant < zbin_oq_low)) && (Retries < 10)) + { + vp8_update_rate_correction_factors(cpi, 0); + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + Retries ++; + } + } + + overshoot_seen = TRUE; + } + else + { + if (cpi->zbin_over_quant == 0) + q_high = (Q > q_low) ? (Q - 1) : q_low; // Lower q_high if not using over quant + else // else lower zbin_oq_high + zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low; + + if (overshoot_seen) + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 1); + + Q = (q_high + q_low) / 2; + + // Adjust cpi->zbin_over_quant (only allowed when Q is max) + if (Q < MAXQ) + cpi->zbin_over_quant = 0; + else + cpi->zbin_over_quant = (zbin_oq_high + zbin_oq_low) / 2; + } + else + { + // Update rate_correction_factor unless cpi->active_worst_quality has changed. + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 0); + + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + + while (((Q > q_high) || (cpi->zbin_over_quant > zbin_oq_high)) && (Retries < 10)) + { + vp8_update_rate_correction_factors(cpi, 0); + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + Retries ++; + } + } + + undershoot_seen = TRUE; + } + + // Clamp Q to upper and lower limits: + if (Q > q_high) + Q = q_high; + else if (Q < q_low) + Q = q_low; + + // Clamp cpi->zbin_over_quant + cpi->zbin_over_quant = (cpi->zbin_over_quant < zbin_oq_low) ? zbin_oq_low : (cpi->zbin_over_quant > zbin_oq_high) ? zbin_oq_high : cpi->zbin_over_quant; + + //Loop = ((Q != last_q) || (last_zbin_oq != cpi->zbin_over_quant)) ? TRUE : FALSE; + Loop = ((Q != last_q)) ? TRUE : FALSE; + last_zbin_oq = cpi->zbin_over_quant; + } + else +#endif + Loop = FALSE; + + if (cpi->is_src_frame_alt_ref) + Loop = FALSE; + + if (Loop == TRUE) + { + vp8_restore_coding_context(cpi); + loop_count++; +#if CONFIG_PSNR + cpi->tot_recode_hits++; +#endif + } + } + while (Loop == TRUE); + +#if 0 + // Experimental code for lagged and one pass + // Update stats used for one pass GF selection + { + /* + int frames_so_far; + double frame_intra_error; + double frame_coded_error; + double frame_pcnt_inter; + double frame_pcnt_motion; + double frame_mvr; + double frame_mvr_abs; + double frame_mvc; + double frame_mvc_abs; + */ + + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_coded_error = (double)cpi->prediction_error; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_intra_error = (double)cpi->intra_error; + cpi->one_pass_frame_stats[cpi->one_pass_frame_index].frame_pcnt_inter = (double)(100 - cpi->this_frame_percent_intra) / 100.0; + } +#endif + + // Update the GF useage maps. + // This is done after completing the compression of a frame when all modes etc. are finalized but before loop filter + vp8_update_gf_useage_maps(cm, &cpi->mb.e_mbd); + + if (cm->frame_type == KEY_FRAME) + cm->refresh_last_frame = 1; + + if (0) + { + FILE *f = fopen("gfactive.stt", "a"); + fprintf(f, "%8d %8d %8d %8d %8d\n", cm->current_video_frame, (100 * cpi->common.gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols), cpi->this_iiratio, cpi->next_iiratio, cm->refresh_golden_frame); + fclose(f); + } + + // For inter frames the current default behaviour is that when cm->refresh_golden_frame is set we copy the old GF over to the ARF buffer + // This is purely an encoder descision at present. + if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame) + cm->copy_buffer_to_arf = 2; + else + cm->copy_buffer_to_arf = 0; + + if (cm->refresh_last_frame) + { + vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); + cm->frame_to_show = &cm->last_frame; + } + else + cm->frame_to_show = &cm->new_frame; + + + + //#pragma omp parallel sections + { + + //#pragma omp section + { + + struct vpx_usec_timer timer; + + vpx_usec_timer_start(&timer); + + if (cpi->sf.auto_filter == 0) + vp8cx_pick_filter_level_fast(cpi->Source, cpi); + else + vp8cx_pick_filter_level(cpi->Source, cpi); + + vpx_usec_timer_mark(&timer); + + cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); + + if (cm->no_lpf) + cm->filter_level = 0; + + if (cm->filter_level > 0) + { + vp8cx_set_alt_lf_level(cpi, cm->filter_level); + vp8_loop_filter_frame(cm, &cpi->mb.e_mbd, cm->filter_level); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + } + + vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); + + if (cpi->oxcf.error_resilient_mode == 1) + { + cm->refresh_entropy_probs = 0; + } + + } +//#pragma omp section + { + // build the bitstream + vp8_pack_bitstream(cpi, dest, size); + } + } + + + // At this point the new frame has been encoded coded. + // If any buffer copy / swaping is signalled it should be done here. + if (cm->frame_type == KEY_FRAME) + { + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); + } + else // For non key frames + { + // Code to copy between reference buffers + if (cm->copy_buffer_to_arf) + { + if (cm->copy_buffer_to_arf == 1) + { + if (cm->refresh_last_frame) + // We copy new_frame here because last and new buffers will already have been swapped if cm->refresh_last_frame is set. + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->alt_ref_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->alt_ref_frame); + } + else if (cm->copy_buffer_to_arf == 2) + vp8_yv12_copy_frame_ptr(&cm->golden_frame, &cm->alt_ref_frame); + } + + if (cm->copy_buffer_to_gf) + { + if (cm->copy_buffer_to_gf == 1) + { + if (cm->refresh_last_frame) + // We copy new_frame here because last and new buffers will already have been swapped if cm->refresh_last_frame is set. + vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->golden_frame); + else + vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); + } + else if (cm->copy_buffer_to_gf == 2) + vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, &cm->golden_frame); + } + } + + // Update rate control heuristics + cpi->total_byte_count += (*size); + cpi->projected_frame_size = (*size) << 3; + + if (!active_worst_qchanged) + vp8_update_rate_correction_factors(cpi, 2); + + cpi->last_q[cm->frame_type] = cm->base_qindex; + + if (cm->frame_type == KEY_FRAME) + { + vp8_adjust_key_frame_context(cpi); + } + + // Keep a record of ambient average Q. + if (cm->frame_type == KEY_FRAME) + cpi->avg_frame_qindex = cm->base_qindex; + else + cpi->avg_frame_qindex = (2 + 3 * cpi->avg_frame_qindex + cm->base_qindex) >> 2; + + // Keep a record from which we can calculate the average Q excluding GF updates and key frames + if ((cm->frame_type != KEY_FRAME) && !cm->refresh_golden_frame && !cm->refresh_alt_ref_frame) + { + cpi->ni_frames++; + + // Calculate the average Q for normal inter frames (not key or GFU frames) + // This is used as a basis for setting active worst quality. + if (cpi->ni_frames > 150) + { + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = (cpi->ni_tot_qi / cpi->ni_frames); + } + // Early in the clip ... average the current frame Q value with the default + // entered by the user as a dampening measure + else + { + cpi->ni_tot_qi += Q; + cpi->ni_av_qi = ((cpi->ni_tot_qi / cpi->ni_frames) + cpi->worst_quality + 1) / 2; + } + + // If the average Q is higher than what was used in the last frame + // (after going through the recode loop to keep the frame size within range) + // then use the last frame value - 1. + // The -1 is designed to stop Q and hence the data rate, from progressively + // falling away during difficult sections, but at the same time reduce the number of + // itterations around the recode loop. + if (Q > cpi->ni_av_qi) + cpi->ni_av_qi = Q - 1; + + } + +#if 0 + + // If the frame was massively oversize and we are below optimal buffer level drop next frame + if ((cpi->drop_frames_allowed) && + (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && + (cpi->projected_frame_size > (4 * cpi->this_frame_target))) + { + cpi->drop_frame = TRUE; + } + +#endif + + // Set the count for maximum consequative dropped frames based upon the ratio of + // this frame size to the target average per frame bandwidth. + // (cpi->av_per_frame_bandwidth > 0) is just a sanity check to prevent / 0. + if (cpi->drop_frames_allowed && (cpi->av_per_frame_bandwidth > 0)) + { + cpi->max_drop_count = cpi->projected_frame_size / cpi->av_per_frame_bandwidth; + + if (cpi->max_drop_count > cpi->max_consec_dropped_frames) + cpi->max_drop_count = cpi->max_consec_dropped_frames; + } + + // Update the buffer level variable. + if (cpi->common.refresh_alt_ref_frame) + cpi->bits_off_target -= cpi->projected_frame_size; + else + cpi->bits_off_target += cpi->av_per_frame_bandwidth - cpi->projected_frame_size; + + // Rolling monitors of whether we are over or underspending used to help regulate min and Max Q in two pass. + cpi->rolling_target_bits = ((cpi->rolling_target_bits * 3) + cpi->this_frame_target + 2) / 4; + cpi->rolling_actual_bits = ((cpi->rolling_actual_bits * 3) + cpi->projected_frame_size + 2) / 4; + cpi->long_rolling_target_bits = ((cpi->long_rolling_target_bits * 31) + cpi->this_frame_target + 16) / 32; + cpi->long_rolling_actual_bits = ((cpi->long_rolling_actual_bits * 31) + cpi->projected_frame_size + 16) / 32; + + // Actual bits spent + cpi->total_actual_bits += cpi->projected_frame_size; + + // Debug stats + cpi->total_target_vs_actual += (cpi->this_frame_target - cpi->projected_frame_size); + + cpi->buffer_level = cpi->bits_off_target; + + // Update bits left to the kf and gf groups to account for overshoot or undershoot on these frames + if (cm->frame_type == KEY_FRAME) + { + cpi->kf_group_bits += cpi->this_frame_target - cpi->projected_frame_size; + + if (cpi->kf_group_bits < 0) + cpi->kf_group_bits = 0 ; + } + else if (cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + { + cpi->gf_group_bits += cpi->this_frame_target - cpi->projected_frame_size; + + if (cpi->gf_group_bits < 0) + cpi->gf_group_bits = 0 ; + } + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->common.refresh_alt_ref_frame) + { + cpi->last_skip_false_probs[2] = cpi->prob_skip_false; + cpi->last_skip_probs_q[2] = cm->base_qindex; + } + else if (cpi->common.refresh_golden_frame) + { + cpi->last_skip_false_probs[1] = cpi->prob_skip_false; + cpi->last_skip_probs_q[1] = cm->base_qindex; + } + else + { + cpi->last_skip_false_probs[0] = cpi->prob_skip_false; + cpi->last_skip_probs_q[0] = cm->base_qindex; + + //update the baseline + cpi->base_skip_false_prob[cm->base_qindex] = cpi->prob_skip_false; + + } + } + +#if CONFIG_PSNR + + if (0) + { + FILE *f = fopen("tmp.stt", "a"); + + vp8_clear_system_state(); //__asm emms; + + if (cpi->total_coded_error_left != 0.0) + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %6ld %6ld %6ld %6ld %5ld %5ld %5ld %8ld %8.2f %10d %10.3f %10.3f %8ld\n", cpi->common.current_video_frame, cpi->this_frame_target, cpi->projected_frame_size, (cpi->projected_frame_size - cpi->this_frame_target), (int)cpi->total_target_vs_actual, (cpi->oxcf.starting_buffer_level - cpi->bits_off_target), (int)cpi->total_actual_bits, cm->base_qindex, cpi->active_best_quality, cpi->active_worst_quality, cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, cpi->est_max_qcorrection_factor, (int)cpi->bits_left, cpi->total_coded_error_left, (double)cpi->bits_left / cpi->total_coded_error_left, cpi->tot_recode_hits); + else + fprintf(f, "%10d %10d %10d %10d %10d %10d %10d %10d %6ld %6ld %6ld %6ld %5ld %5ld %5ld %8ld %8.2f %10d %10.3f %8ld\n", cpi->common.current_video_frame, cpi->this_frame_target, cpi->projected_frame_size, (cpi->projected_frame_size - cpi->this_frame_target), (int)cpi->total_target_vs_actual, (cpi->oxcf.starting_buffer_level - cpi->bits_off_target), (int)cpi->total_actual_bits, cm->base_qindex, cpi->active_best_quality, cpi->active_worst_quality, cpi->avg_frame_qindex, cpi->zbin_over_quant, cm->refresh_golden_frame, cm->refresh_alt_ref_frame, cm->frame_type, cpi->gfu_boost, cpi->est_max_qcorrection_factor, (int)cpi->bits_left, cpi->total_coded_error_left, cpi->tot_recode_hits); + + fclose(f); + + { + FILE *fmodes = fopen("Modes.stt", "a"); + int i; + + fprintf(fmodes, "%6d:%1d:%1d:%1d ", cpi->common.current_video_frame, cm->frame_type, cm->refresh_golden_frame, cm->refresh_alt_ref_frame); + + for (i = 0; i < MAX_MODES; i++) + fprintf(fmodes, "%5d ", cpi->mode_chosen_counts[i]); + + fprintf(fmodes, "\n"); + + fclose(fmodes); + } + } + +#endif + + // If this was a kf or Gf note the Q + if ((cm->frame_type == KEY_FRAME) || cm->refresh_golden_frame || cm->refresh_alt_ref_frame) + cm->last_kf_gf_q = cm->base_qindex; + + if (cm->refresh_golden_frame == 1) + cm->frame_flags = cm->frame_flags | FRAMEFLAGS_GOLDEN; + else + cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_GOLDEN; + + if (cm->refresh_alt_ref_frame == 1) + cm->frame_flags = cm->frame_flags | FRAMEFLAGS_ALTREF; + else + cm->frame_flags = cm->frame_flags&~FRAMEFLAGS_ALTREF; + + + if (cm->refresh_last_frame & cm->refresh_golden_frame) // both refreshed + cpi->gold_is_last = 1; + else if (cm->refresh_last_frame ^ cm->refresh_golden_frame) // 1 refreshed but not the other + cpi->gold_is_last = 0; + + if (cm->refresh_last_frame & cm->refresh_alt_ref_frame) // both refreshed + cpi->alt_is_last = 1; + else if (cm->refresh_last_frame ^ cm->refresh_alt_ref_frame) // 1 refreshed but not the other + cpi->alt_is_last = 0; + + if (cm->refresh_alt_ref_frame & cm->refresh_golden_frame) // both refreshed + cpi->gold_is_alt = 1; + else if (cm->refresh_alt_ref_frame ^ cm->refresh_golden_frame) // 1 refreshed but not the other + cpi->gold_is_alt = 0; + + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + if (cpi->gold_is_last) + cpi->ref_frame_flags &= !VP8_GOLD_FLAG; + + if (cpi->alt_is_last) + cpi->ref_frame_flags &= !VP8_ALT_FLAG; + + if (cpi->gold_is_alt) + cpi->ref_frame_flags &= !VP8_ALT_FLAG; + + + if (cpi->oxcf.error_resilient_mode) + { + // Is this an alternate reference update + if (cpi->common.refresh_alt_ref_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); + + if (cpi->common.refresh_golden_frame) + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); + } + else + { + if (cpi->oxcf.play_alternate && cpi->common.refresh_alt_ref_frame) + // Update the alternate reference frame and stats as appropriate. + update_alt_ref_frame_and_stats(cpi); + else + // Update the Golden frame and golden frame and stats as appropriate. + update_golden_frame_and_stats(cpi); + } + + if (cm->frame_type == KEY_FRAME) + { + // Tell the caller that the frame was coded as a key frame + *frame_flags = cm->frame_flags | FRAMEFLAGS_KEY; + + // As this frame is a key frame the next defaults to an inter frame. + cm->frame_type = INTER_FRAME; + + cpi->last_frame_percent_intra = 100; + } + else + { + *frame_flags = cm->frame_flags&~FRAMEFLAGS_KEY; + + cpi->last_frame_percent_intra = cpi->this_frame_percent_intra; + } + + // Clear the one shot update flags for segmentation map and mode/ref loop filter deltas. + cpi->mb.e_mbd.update_mb_segmentation_map = 0; + cpi->mb.e_mbd.update_mb_segmentation_data = 0; + cpi->mb.e_mbd.mode_ref_lf_delta_update = 0; + + + // Dont increment frame counters if this was an altref buffer update not a real frame + if (cm->show_frame) + { + cm->current_video_frame++; + cpi->frames_since_key++; + } + + // reset to normal state now that we are done. + + + + if (0) + { + char filename[512]; + FILE *recon_file; + sprintf(filename, "enc%04d.yuv", (int) cm->current_video_frame); + recon_file = fopen(filename, "wb"); + fwrite(cm->last_frame.buffer_alloc, cm->last_frame.frame_size, 1, recon_file); + fclose(recon_file); + } + + // DEBUG + //vp8_write_yuv_frame("encoder_recon.yuv", cm->frame_to_show); + + +} + +int vp8_is_gf_update_needed(VP8_PTR ptr) +{ + VP8_COMP *cpi = (VP8_COMP *) ptr; + int ret_val; + + ret_val = cpi->gf_update_recommended; + cpi->gf_update_recommended = 0; + + return ret_val; +} + +void vp8_check_gf_quality(VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + int gf_active_pct = (100 * cm->gf_active_count) / (cm->mb_rows * cm->mb_cols); + int gf_ref_usage_pct = (cpi->count_mb_ref_frame_usage[GOLDEN_FRAME] * 100) / (cm->mb_rows * cm->mb_cols); + int last_ref_zz_useage = (cpi->inter_zz_count * 100) / (cm->mb_rows * cm->mb_cols); + + // Gf refresh is not currently being signalled + if (cpi->gf_update_recommended == 0) + { + if (cpi->common.frames_since_golden > 7) + { + // Low use of gf + if ((gf_active_pct < 10) || ((gf_active_pct + gf_ref_usage_pct) < 15)) + { + // ...but last frame zero zero usage is reasonbable so a new gf might be appropriate + if (last_ref_zz_useage >= 25) + { + cpi->gf_bad_count ++; + + if (cpi->gf_bad_count >= 8) // Check that the condition is stable + { + cpi->gf_update_recommended = 1; + cpi->gf_bad_count = 0; + } + } + else + cpi->gf_bad_count = 0; // Restart count as the background is not stable enough + } + else + cpi->gf_bad_count = 0; // Gf useage has picked up so reset count + } + } + // If the signal is set but has not been read should we cancel it. + else if (last_ref_zz_useage < 15) + { + cpi->gf_update_recommended = 0; + cpi->gf_bad_count = 0; + } + +#if 0 + + if (0) + { + FILE *f = fopen("gfneeded.stt", "a"); + fprintf(f, "%10d %10d %10d %10d %10ld \n", + cm->current_video_frame, + cpi->common.frames_since_golden, + gf_active_pct, gf_ref_usage_pct, + cpi->gf_update_recommended); + fclose(f); + } + +#endif +} + +#if !(CONFIG_REALTIME_ONLY) +static void Pass2Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest, unsigned int *frame_flags) +{ + double two_pass_min_rate = (double)(cpi->oxcf.target_bandwidth * cpi->oxcf.two_pass_vbrmin_section / 100); + + if (!cpi->common.refresh_alt_ref_frame) + vp8_second_pass(cpi); + + encode_frame_to_data_rate(cpi, size, dest, frame_flags); + cpi->bits_left -= 8 * *size; + + if (!cpi->common.refresh_alt_ref_frame) + cpi->bits_left += (long long)(two_pass_min_rate / cpi->oxcf.frame_rate); +} +#endif + +//For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us. +#if HAVE_ARMV7 +extern void vp8_push_neon(INT64 *store); +extern void vp8_pop_neon(INT64 *store); +static INT64 store_reg[8]; +#endif +int vp8_receive_raw_frame(VP8_PTR ptr, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, INT64 time_stamp, INT64 end_time) +{ + VP8_COMP *cpi = (VP8_COMP *) ptr; + VP8_COMMON *cm = &cpi->common; + struct vpx_usec_timer timer; + + if (!cpi) + return -1; + +#if HAVE_ARMV7 + vp8_push_neon(store_reg); +#endif + + vpx_usec_timer_start(&timer); + + // no more room for frames; + if (cpi->source_buffer_count != 0 && cpi->source_buffer_count >= cpi->oxcf.lag_in_frames) + { +#if HAVE_ARMV7 + vp8_pop_neon(store_reg); +#endif + return -1; + } + + //printf("in-cpi->source_buffer_count: %d\n", cpi->source_buffer_count); + + cm->clr_type = sd->clrtype; + + // make a copy of the frame for use later... +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->oxcf.allow_lag) + { + int which_buffer = cpi->source_encode_index - 1; + SOURCE_SAMPLE *s; + + if (which_buffer == -1) + which_buffer = cpi->oxcf.lag_in_frames - 1; + + if (cpi->source_buffer_count < cpi->oxcf.lag_in_frames - 1) + which_buffer = cpi->source_buffer_count; + + s = &cpi->src_buffer[which_buffer]; + + s->source_time_stamp = time_stamp; + s->source_end_time_stamp = end_time; + s->source_frame_flags = frame_flags; + vp8_yv12_copy_frame_ptr(sd, &s->source_buffer); + + cpi->source_buffer_count ++; + } + else +#endif + { + SOURCE_SAMPLE *s; + s = &cpi->src_buffer[0]; + s->source_end_time_stamp = end_time; + s->source_time_stamp = time_stamp; + s->source_frame_flags = frame_flags; +#if HAVE_ARMV7 + vp8_yv12_copy_src_frame_func_neon(sd, &s->source_buffer); +#else + vp8_yv12_copy_frame_ptr(sd, &s->source_buffer); +#endif + cpi->source_buffer_count = 1; + } + + vpx_usec_timer_mark(&timer); + cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); + +#if HAVE_ARMV7 + vp8_pop_neon(store_reg); +#endif + + return 0; +} +int vp8_get_compressed_data(VP8_PTR ptr, unsigned int *frame_flags, unsigned long *size, unsigned char *dest, INT64 *time_stamp, INT64 *time_end, int flush) +{ + + VP8_COMP *cpi = (VP8_COMP *) ptr; + VP8_COMMON *cm = &cpi->common; + struct vpx_usec_timer tsctimer; + struct vpx_usec_timer ticktimer; + struct vpx_usec_timer cmptimer; + + if (!cpi) + return -1; + +#if HAVE_ARMV7 + vp8_push_neon(store_reg); +#endif + + vpx_usec_timer_start(&cmptimer); + + + // flush variable tells us that even though we have less than 10 frames + // in our buffer we need to start producing compressed frames. + // Probably because we are at the end of a file.... + if ((cpi->source_buffer_count == cpi->oxcf.lag_in_frames && cpi->oxcf.lag_in_frames > 0) + || (!cpi->oxcf.allow_lag && cpi->source_buffer_count > 0) + || (flush && cpi->source_buffer_count > 0)) + { + + SOURCE_SAMPLE *s; + + s = &cpi->src_buffer[cpi->source_encode_index]; + cpi->source_time_stamp = s->source_time_stamp; + cpi->source_end_time_stamp = s->source_end_time_stamp; + +#if !(CONFIG_REALTIME_ONLY) + + // Should we code an alternate reference frame + if (cpi->oxcf.error_resilient_mode == 0 && + cpi->oxcf.play_alternate && + cpi->source_alt_ref_pending && + (cpi->frames_till_gf_update_due < cpi->source_buffer_count) && + cpi->oxcf.lag_in_frames != 0) + { + cpi->last_alt_ref_sei = (cpi->source_encode_index + cpi->frames_till_gf_update_due) % cpi->oxcf.lag_in_frames; + +#if VP8_TEMPORAL_ALT_REF + + if (cpi->oxcf.arnr_max_frames > 0) + { +#if 0 + // my attempt at a loop that tests the results of strength filter. + int start_frame = cpi->last_alt_ref_sei - 3; + + int i, besti = -1, pastin = cpi->oxcf.arnr_strength; + + int besterr; + + if (start_frame < 0) + start_frame += cpi->oxcf.lag_in_frames; + + besterr = vp8_calc_low_ss_err(&cpi->src_buffer[cpi->last_alt_ref_sei].source_buffer, + &cpi->src_buffer[start_frame].source_buffer, IF_RTCD(&cpi->rtcd.variance)); + + for (i = 0; i < 7; i++) + { + int thiserr; + cpi->oxcf.arnr_strength = i; + vp8cx_temp_filter_c(cpi); + + thiserr = vp8_calc_low_ss_err(&cpi->alt_ref_buffer.source_buffer, + &cpi->src_buffer[start_frame].source_buffer, IF_RTCD(&cpi->rtcd.variance)); + + if (10 * thiserr < besterr * 8) + { + besterr = thiserr; + besti = i; + } + } + + if (besti != -1) + { + cpi->oxcf.arnr_strength = besti; + vp8cx_temp_filter_c(cpi); + s = &cpi->alt_ref_buffer; + + // FWG not sure if I need to copy this data for the Alt Ref frame + s->source_time_stamp = cpi->src_buffer[cpi->last_alt_ref_sei].source_time_stamp; + s->source_end_time_stamp = cpi->src_buffer[cpi->last_alt_ref_sei].source_end_time_stamp; + s->source_frame_flags = cpi->src_buffer[cpi->last_alt_ref_sei].source_frame_flags; + } + else + s = &cpi->src_buffer[cpi->last_alt_ref_sei]; + +#else + vp8cx_temp_filter_c(cpi); + s = &cpi->alt_ref_buffer; + + // FWG not sure if I need to copy this data for the Alt Ref frame + s->source_time_stamp = cpi->src_buffer[cpi->last_alt_ref_sei].source_time_stamp; + s->source_end_time_stamp = cpi->src_buffer[cpi->last_alt_ref_sei].source_end_time_stamp; + s->source_frame_flags = cpi->src_buffer[cpi->last_alt_ref_sei].source_frame_flags; + +#endif + } + else +#endif + s = &cpi->src_buffer[cpi->last_alt_ref_sei]; + + cm->frames_till_alt_ref_frame = cpi->frames_till_gf_update_due; + cm->refresh_alt_ref_frame = 1; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 0; + cm->show_frame = 0; + cpi->source_alt_ref_pending = FALSE; // Clear Pending altf Ref flag. + cpi->is_src_frame_alt_ref = 0; + } + else +#endif + { + cm->show_frame = 1; +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->oxcf.allow_lag) + { + if (cpi->source_encode_index == cpi->last_alt_ref_sei) + { +#if VP8_TEMPORAL_ALT_REF + + if (cpi->oxcf.arnr_max_frames == 0) + { + cpi->is_src_frame_alt_ref = 1; // copy alt ref + } + else + { + cpi->is_src_frame_alt_ref = 0; + } + +#else + cpi->is_src_frame_alt_ref = 1; +#endif + cpi->last_alt_ref_sei = -1; + } + else + cpi->is_src_frame_alt_ref = 0; + + cpi->source_encode_index = (cpi->source_encode_index + 1) % cpi->oxcf.lag_in_frames; + } + +#endif + cpi->source_buffer_count--; + } + + cpi->un_scaled_source = &s->source_buffer; + cpi->Source = &s->source_buffer; + cpi->source_frame_flags = s->source_frame_flags; + + *time_stamp = cpi->source_time_stamp; + *time_end = cpi->source_end_time_stamp; + } + else + { + *size = 0; +#if !(CONFIG_REALTIME_ONLY) + + if (flush && cpi->pass == 1 && !cpi->first_pass_done) + { + vp8_end_first_pass(cpi); /* get last stats packet */ + cpi->first_pass_done = 1; + } + +#endif + +#if HAVE_ARMV7 + vp8_pop_neon(store_reg); +#endif + return -1; + } + + *frame_flags = cpi->source_frame_flags; + +#if CONFIG_PSNR + + if (cpi->source_time_stamp < cpi->first_time_stamp_ever) + cpi->first_time_stamp_ever = cpi->source_time_stamp; + +#endif + + // adjust frame rates based on timestamps given + if (!cm->refresh_alt_ref_frame) + { + if (cpi->last_time_stamp_seen == 0) + { + double this_fps = 10000000.000 / (cpi->source_end_time_stamp - cpi->source_time_stamp); + + vp8_new_frame_rate(cpi, this_fps); + } + else + { + long long nanosecs = cpi->source_time_stamp - cpi->last_time_stamp_seen; + double this_fps = 10000000.000 / nanosecs; + + vp8_new_frame_rate(cpi, (7 * cpi->oxcf.frame_rate + this_fps) / 8); + + } + + cpi->last_time_stamp_seen = cpi->source_time_stamp; + } + + if (cpi->compressor_speed == 2) + { + vp8_check_gf_quality(cpi); + } + + if (!cpi) + { +#if HAVE_ARMV7 + vp8_pop_neon(store_reg); +#endif + return 0; + } + + if (cpi->compressor_speed == 2) + { + vpx_usec_timer_start(&tsctimer); + vpx_usec_timer_start(&ticktimer); + } + + // start with a 0 size frame + *size = 0; + + // Clear down mmx registers + vp8_clear_system_state(); //__asm emms; + + cm->frame_type = INTER_FRAME; + cm->frame_flags = *frame_flags; + +#if 0 + + if (cm->refresh_alt_ref_frame) + { + //cm->refresh_golden_frame = 1; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 0; + } + else + { + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + } + +#endif + +#if !(CONFIG_REALTIME_ONLY) + + if (cpi->pass == 1) + { + Pass1Encode(cpi, size, dest, frame_flags); + } + else if (cpi->pass == 2) + { + Pass2Encode(cpi, size, dest, frame_flags); + } + else +#endif + encode_frame_to_data_rate(cpi, size, dest, frame_flags); + + if (cpi->compressor_speed == 2) + { + unsigned int duration, duration2; + vpx_usec_timer_mark(&tsctimer); + vpx_usec_timer_mark(&ticktimer); + + duration = vpx_usec_timer_elapsed(&ticktimer); + duration2 = (unsigned int)((double)duration / 2); + + if (cm->frame_type != KEY_FRAME) + { + if (cpi->avg_encode_time == 0) + cpi->avg_encode_time = duration; + else + cpi->avg_encode_time = (7 * cpi->avg_encode_time + duration) >> 3; + } + + if (duration2) + { + //if(*frame_flags!=1) + { + + if (cpi->avg_pick_mode_time == 0) + cpi->avg_pick_mode_time = duration2; + else + cpi->avg_pick_mode_time = (7 * cpi->avg_pick_mode_time + duration2) >> 3; + } + } + + } + + if (cm->refresh_entropy_probs == 0) + { + vpx_memcpy(&cm->fc, &cm->lfc, sizeof(cm->fc)); + } + + // if its a dropped frame honor the requests on subsequent frames + if (*size > 0) + { + + // return to normal state + cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; + + cm->refresh_entropy_probs = 1; + cm->refresh_alt_ref_frame = 0; + cm->refresh_golden_frame = 0; + cm->refresh_last_frame = 1; + cm->frame_type = INTER_FRAME; + + } + + cpi->ready_for_new_frame = 1; + + vpx_usec_timer_mark(&cmptimer); + cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); + + if (cpi->b_calculate_psnr && cpi->pass != 1 && cm->show_frame) + generate_psnr_packet(cpi); + +#if CONFIG_PSNR + + if (cpi->pass != 1) + { + cpi->bytes += *size; + + if (cm->show_frame) + { + + cpi->count ++; + + if (cpi->b_calculate_psnr) + { + double y, u, v; + double sq_error; + double frame_psnr = vp8_calc_psnr(cpi->Source, cm->frame_to_show, &y, &u, &v, &sq_error); + + cpi->total_y += y; + cpi->total_u += u; + cpi->total_v += v; + cpi->total_sq_error += sq_error; + cpi->total += frame_psnr; + { + double y2, u2, v2, frame_psnr2, frame_ssim2 = 0; + double weight = 0; + + vp8_deblock(cm->frame_to_show, &cm->post_proc_buffer, cm->filter_level * 10 / 6, 1, 0, IF_RTCD(&cm->rtcd.postproc)); + vp8_clear_system_state(); + frame_psnr2 = vp8_calc_psnr(cpi->Source, &cm->post_proc_buffer, &y2, &u2, &v2, &sq_error); + frame_ssim2 = vp8_calc_ssim(cpi->Source, &cm->post_proc_buffer, 1, &weight); + + cpi->summed_quality += frame_ssim2 * weight; + cpi->summed_weights += weight; + + cpi->totalp_y += y2; + cpi->totalp_u += u2; + cpi->totalp_v += v2; + cpi->totalp += frame_psnr2; + cpi->total_sq_error2 += sq_error; + + } + } + + if (cpi->b_calculate_ssimg) + { + double y, u, v, frame_all; + frame_all = vp8_calc_ssimg(cpi->Source, cm->frame_to_show, &y, &u, &v); + cpi->total_ssimg_y += y; + cpi->total_ssimg_u += u; + cpi->total_ssimg_v += v; + cpi->total_ssimg_all += frame_all; + } + + } + } + +#if 0 + + if (cpi->common.frame_type != 0 && cpi->common.base_qindex == cpi->oxcf.worst_allowed_q) + { + skiptruecount += cpi->skip_true_count; + skipfalsecount += cpi->skip_false_count; + } + +#endif +#if 0 + + if (cpi->pass != 1) + { + FILE *f = fopen("skip.stt", "a"); + fprintf(f, "frame:%4d flags:%4x Q:%4d P:%4d Size:%5d\n", cpi->common.current_video_frame, *frame_flags, cpi->common.base_qindex, cpi->prob_skip_false, *size); + + if (cpi->is_src_frame_alt_ref == 1) + fprintf(f, "skipcount: %4d framesize: %d\n", cpi->skip_true_count , *size); + + fclose(f); + } + +#endif +#endif + +#if HAVE_ARMV7 + vp8_pop_neon(store_reg); +#endif + + return 0; +} + +int vp8_get_preview_raw_frame(VP8_PTR comp, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags) +{ + VP8_COMP *cpi = (VP8_COMP *) comp; + + if (cpi->common.refresh_alt_ref_frame) + return -1; + else + { + int ret; +#if CONFIG_POSTPROC + ret = vp8_post_proc_frame(&cpi->common, dest, deblock_level, noise_level, flags); +#else + + if (cpi->common.frame_to_show) + { + *dest = *cpi->common.frame_to_show; + dest->y_width = cpi->common.Width; + dest->y_height = cpi->common.Height; + dest->uv_height = cpi->common.Height / 2; + ret = 0; + } + else + { + ret = -1; + } + +#endif //!CONFIG_POSTPROC + vp8_clear_system_state(); + return ret; + } +} + +int vp8_set_roimap(VP8_PTR comp, unsigned char *map, unsigned int rows, unsigned int cols, int delta_q[4], int delta_lf[4], unsigned int threshold[4]) +{ + VP8_COMP *cpi = (VP8_COMP *) comp; + signed char feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; + + if (cpi->common.mb_rows != rows || cpi->common.mb_cols != cols) + return -1; + + if (!map) + { + disable_segmentation((VP8_PTR)cpi); + return 0; + } + + // Set the segmentation Map + set_segmentation_map((VP8_PTR)cpi, map); + + // Activate segmentation. + enable_segmentation((VP8_PTR)cpi); + + // Set up the quant segment data + feature_data[MB_LVL_ALT_Q][0] = delta_q[0]; + feature_data[MB_LVL_ALT_Q][1] = delta_q[1]; + feature_data[MB_LVL_ALT_Q][2] = delta_q[2]; + feature_data[MB_LVL_ALT_Q][3] = delta_q[3]; + + // Set up the loop segment data s + feature_data[MB_LVL_ALT_LF][0] = delta_lf[0]; + feature_data[MB_LVL_ALT_LF][1] = delta_lf[1]; + feature_data[MB_LVL_ALT_LF][2] = delta_lf[2]; + feature_data[MB_LVL_ALT_LF][3] = delta_lf[3]; + + cpi->segment_encode_breakout[0] = threshold[0]; + cpi->segment_encode_breakout[1] = threshold[1]; + cpi->segment_encode_breakout[2] = threshold[2]; + cpi->segment_encode_breakout[3] = threshold[3]; + + // Initialise the feature data structure + // SEGMENT_DELTADATA 0, SEGMENT_ABSDATA 1 + set_segment_data((VP8_PTR)cpi, &feature_data[0][0], SEGMENT_DELTADATA); + + return 0; +} + +int vp8_set_active_map(VP8_PTR comp, unsigned char *map, unsigned int rows, unsigned int cols) +{ + VP8_COMP *cpi = (VP8_COMP *) comp; + + if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) + { + if (map) + { + vpx_memcpy(cpi->active_map, map, rows * cols); + cpi->active_map_enabled = 1; + } + else + cpi->active_map_enabled = 0; + + return 0; + } + else + { + //cpi->active_map_enabled = 0; + return -1 ; + } +} + +int vp8_set_internal_size(VP8_PTR comp, VPX_SCALING horiz_mode, VPX_SCALING vert_mode) +{ + VP8_COMP *cpi = (VP8_COMP *) comp; + + if (horiz_mode >= NORMAL && horiz_mode <= ONETWO) + cpi->common.horiz_scale = horiz_mode; + else + return -1; + + if (vert_mode >= NORMAL && vert_mode <= ONETWO) + cpi->common.vert_scale = vert_mode; + else + return -1; + + return 0; +} + + + +int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd) +{ + int i, j; + int Total = 0; + + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + (void)rtcd; + + // Loop through the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < source->y_height; i += 16) + { + for (j = 0; j < source->y_width; j += 16) + { + unsigned int sse; + Total += VARIANCE_INVOKE(rtcd, mse16x16)(src + j, source->y_stride, dst + j, dest->y_stride, &sse); + } + + src += 16 * source->y_stride; + dst += 16 * dest->y_stride; + } + + return Total; +} +int vp8_calc_low_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd) +{ + int i, j; + int Total = 0; + + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + (void)rtcd; + + // Loop through the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < source->y_height; i += 16) + { + for (j = 0; j < source->y_width; j += 16) + { + unsigned int sse, sse2, sum2; + VARIANCE_INVOKE(rtcd, mse16x16)(src + j, source->y_stride, dst + j, dest->y_stride, &sse); + + if (sse < 8096) + Total += sse; + } + + src += 16 * source->y_stride; + dst += 16 * dest->y_stride; + } + + return Total; +} + +int vp8_get_speed(VP8_PTR c) +{ + VP8_COMP *cpi = (VP8_COMP *) c; + return cpi->Speed; +} +int vp8_get_quantizer(VP8_PTR c) +{ + VP8_COMP *cpi = (VP8_COMP *) c; + return cpi->common.base_qindex; +}
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h new file mode 100644 index 0000000..29b120e --- /dev/null +++ b/vp8/encoder/onyx_int.h
@@ -0,0 +1,670 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_VP8_INT_H +#define __INC_VP8_INT_H + +#include <stdio.h> +#include "vpx_ports/config.h" +#include "onyx.h" +#include "treewriter.h" +#include "tokenize.h" +#include "onyxc_int.h" +#include "preproc.h" +#include "variance.h" +#include "dct.h" +#include "encodemb.h" +#include "quantize.h" +#include "entropy.h" +#include "threading.h" +#include "vpx_ports/mem.h" +#include "vpx_codec/internal/vpx_codec_internal.h" +#include "mcomp.h" + +#define INTRARDOPT +//#define SPEEDSTATS 1 +#define MIN_GF_INTERVAL 4 +#define DEFAULT_GF_INTERVAL 7 + +#define KEY_FRAME_CONTEXT 5 + +#define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY? 1 : 25) + +#define AF_THRESH 25 +#define AF_THRESH2 100 +#define ARF_DECAY_THRESH 12 +#define MAX_MODES 20 + +#define MIN_THRESHMULT 32 +#define MAX_THRESHMULT 512 + +#define GF_ZEROMV_ZBIN_BOOST 24 +#define ZBIN_OQ_MAX 192 + +#define VP8_TEMPORAL_ALT_REF 1 + +typedef struct +{ + int kf_indicated; + unsigned int frames_since_key; + unsigned int frames_since_golden; + int filter_level; + int frames_till_gf_update_due; + int recent_ref_frame_usage[MAX_REF_FRAMES]; + + MV_CONTEXT mvc[2]; + int mvcosts[2][MVvals+1]; + +#ifdef MODE_STATS + // Stats + int y_modes[5]; + int uv_modes[4]; + int b_modes[10]; + int inter_y_modes[10]; + int inter_uv_modes[4]; + int inter_b_modes[10]; +#endif + + vp8_prob ymode_prob[4], uv_mode_prob[3]; /* interframe intra mode probs */ + vp8_prob kf_ymode_prob[4], kf_uv_mode_prob[3]; /* keyframe "" */ + + int ymode_count[5], uv_mode_count[4]; /* intra MB type cts this frame */ + + int count_mb_ref_frame_usage[MAX_REF_FRAMES]; + + int this_frame_percent_intra; + int last_frame_percent_intra; + + +} CODING_CONTEXT; + +typedef struct +{ + double frame; + double intra_error; + double coded_error; + double ssim_weighted_pred_err; + double pcnt_inter; + double pcnt_motion; + double pcnt_second_ref; + double MVr; + double mvr_abs; + double MVc; + double mvc_abs; + double MVrv; + double MVcv; + double mv_in_out_count; + double duration; + double count; +} +FIRSTPASS_STATS; + +typedef struct +{ + int frames_so_far; + double frame_intra_error; + double frame_coded_error; + double frame_pcnt_inter; + double frame_pcnt_motion; + double frame_mvr; + double frame_mvr_abs; + double frame_mvc; + double frame_mvc_abs; + +} ONEPASS_FRAMESTATS; + + +typedef enum +{ + THR_ZEROMV = 0, + THR_DC = 1, + + THR_NEARESTMV = 2, + THR_NEARMV = 3, + + THR_ZEROG = 4, + THR_NEARESTG = 5, + + THR_ZEROA = 6, + THR_NEARESTA = 7, + + THR_NEARG = 8, + THR_NEARA = 9, + + THR_V_PRED = 10, + THR_H_PRED = 11, + THR_TM = 12, + + THR_NEWMV = 13, + THR_NEWG = 14, + THR_NEWA = 15, + + THR_SPLITMV = 16, + THR_SPLITG = 17, + THR_SPLITA = 18, + + THR_B_PRED = 19, +} +THR_MODES; + +typedef enum +{ + DIAMOND = 0, + NSTEP = 1, + HEX = 2 +} SEARCH_METHODS; + +typedef struct +{ + int RD; + SEARCH_METHODS search_method; + int improved_quant; + int improved_dct; + int auto_filter; + int recode_loop; + int iterative_sub_pixel; + int half_pixel_search; + int quarter_pixel_search; + int thresh_mult[MAX_MODES]; + int full_freq[2]; + int min_fs_radius; + int max_fs_radius; + int max_step_search_steps; + int first_step; + int optimize_coefficients; + +} SPEED_FEATURES; + +typedef struct +{ + MACROBLOCK mb; + int mb_row; + TOKENEXTRA *tp; + int segment_counts[MAX_MB_SEGMENTS]; + int totalrate; + int current_mb_col; +} MB_ROW_COMP; + +typedef struct +{ + TOKENEXTRA *start; + TOKENEXTRA *stop; +} TOKENLIST; + +typedef struct +{ + int ithread; + void *ptr1; + void *ptr2; +} ENCODETHREAD_DATA; +typedef struct +{ + int ithread; + void *ptr1; +} LPFTHREAD_DATA; + +typedef struct +{ + INT64 source_time_stamp; + INT64 source_end_time_stamp; + + DECLARE_ALIGNED(16, YV12_BUFFER_CONFIG, source_buffer); + unsigned int source_frame_flags; +} SOURCE_SAMPLE; + +typedef struct VP8_ENCODER_RTCD +{ + VP8_COMMON_RTCD *common; + vp8_variance_rtcd_vtable_t variance; + vp8_fdct_rtcd_vtable_t fdct; + vp8_encodemb_rtcd_vtable_t encodemb; + vp8_quantize_rtcd_vtable_t quantize; + vp8_search_rtcd_vtable_t search; +} VP8_ENCODER_RTCD; + +typedef struct +{ + + DECLARE_ALIGNED(16, short, Y1quant[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, Y1zbin[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, Y1round[QINDEX_RANGE][4][4]); + + DECLARE_ALIGNED(16, short, Y2quant[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, Y2zbin[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, Y2round[QINDEX_RANGE][4][4]); + + DECLARE_ALIGNED(16, short, UVquant[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, UVzbin[QINDEX_RANGE][4][4]); + DECLARE_ALIGNED(16, short, UVround[QINDEX_RANGE][4][4]); + + DECLARE_ALIGNED(16, short, zrun_zbin_boost_y1[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, zrun_zbin_boost_y2[QINDEX_RANGE][16]); + DECLARE_ALIGNED(16, short, zrun_zbin_boost_uv[QINDEX_RANGE][16]); + + + MACROBLOCK mb; + VP8_COMMON common; + vp8_writer bc, bc2; + // bool_writer *bc2; + + VP8_CONFIG oxcf; + + YV12_BUFFER_CONFIG *Source; + YV12_BUFFER_CONFIG *un_scaled_source; + INT64 source_time_stamp; + INT64 source_end_time_stamp; + unsigned int source_frame_flags; + YV12_BUFFER_CONFIG scaled_source; + + int source_buffer_count; + int source_encode_index; + int source_alt_ref_pending; + int source_alt_ref_active; + + int last_alt_ref_sei; + int is_src_frame_alt_ref; + + int gold_is_last; // golden frame same as last frame ( short circuit gold searches) + int alt_is_last; // Alt reference frame same as last ( short circuit altref search) + int gold_is_alt; // don't do both alt and gold search ( just do gold). + + //int refresh_alt_ref_frame; + SOURCE_SAMPLE src_buffer[MAX_LAG_BUFFERS]; + + YV12_BUFFER_CONFIG last_frame_uf; + + char *Dest; + + TOKENEXTRA *tok; + unsigned int tok_count; + + + unsigned int frames_since_key; + unsigned int key_frame_frequency; + unsigned int next_key; + + unsigned int mode_check_freq[MAX_MODES]; + unsigned int mode_test_hit_counts[MAX_MODES]; + unsigned int mode_chosen_counts[MAX_MODES]; + unsigned int mbs_tested_so_far; + + unsigned int check_freq[2]; + unsigned int do_full[2]; + + int rd_thresh_mult[MAX_MODES]; + int rd_baseline_thresh[MAX_MODES]; + int rd_threshes[MAX_MODES]; + int mvcostbase; + int mvcostmultiplier; + int subseqblockweight; + int errthresh; + +#ifdef INTRARDOPT + int RDMULT; + int RDDIV ; + + TOKENEXTRA *rdtok; + int intra_rd_opt; + vp8_writer rdbc; + int intra_mode_costs[10]; +#endif + + + CODING_CONTEXT coding_context; + + // Rate targetting variables + long long prediction_error; + long long last_prediction_error; + long long intra_error; + long long last_intra_error; + long long last_auto_filter_prediction_error; + +#if 0 + // Experimental RD code + long long frame_distortion; + long long last_frame_distortion; +#endif + + int last_mb_distortion; + + int frames_since_auto_filter; + + int this_frame_target; + int projected_frame_size; + int last_q[2]; // Separate values for Intra/Inter + int target_bits_per_mb; + + double rate_correction_factor; + double key_frame_rate_correction_factor; + double gf_rate_correction_factor; + double est_max_qcorrection_factor; + + int frames_till_gf_update_due; // Count down till next GF + int current_gf_interval; // GF interval chosen when we coded the last GF + + int gf_overspend_bits; // Total bits overspent becasue of GF boost (cumulative) + + int gf_group_bits; // Projected Bits available for a group of frames including 1 GF or ARF + int gf_bits; // Bits for the golden frame or ARF - 2 pass only + int mid_gf_extra_bits; // A few extra bits for the frame half way between two gfs. + + int kf_group_bits; // Projected total bits available for a key frame group of frames + int kf_group_error_left; // Error score of frames still to be coded in kf group + int kf_bits; // Bits for the key frame in a key frame group - 2 pass only + + int non_gf_bitrate_adjustment; // Used in the few frames following a GF to recover the extra bits spent in that GF + int initial_gf_use; // percentage use of gf 2 frames after gf + + int gf_group_error_left; // Remaining error from uncoded frames in a gf group. Two pass use only + + int kf_overspend_bits; // Extra bits spent on key frames that need to be recovered on inter frames + int kf_bitrate_adjustment; // Current number of bit s to try and recover on each inter frame. + int max_gf_interval; + int baseline_gf_interval; + int gf_decay_rate; + + INT64 key_frame_count; + INT64 tot_key_frame_bits; + int prior_key_frame_size[KEY_FRAME_CONTEXT]; + int prior_key_frame_distance[KEY_FRAME_CONTEXT]; + int per_frame_bandwidth; // Current section per frame bandwidth target + int av_per_frame_bandwidth; // Average frame size target for clip + int min_frame_bandwidth; // Minimum allocation that should be used for any frame + int last_key_frame_size; + int intra_frame_target; + int inter_frame_target; + double output_frame_rate; + long long last_time_stamp_seen; + long long first_time_stamp_ever; + + int ni_av_qi; + int ni_tot_qi; + int ni_frames; + int avg_frame_qindex; + + int zbin_over_quant; + int zbin_mode_boost; + int zbin_mode_boost_enabled; + + INT64 total_byte_count; + + int buffered_mode; + + int buffer_level; + int bits_off_target; + + int rolling_target_bits; + int rolling_actual_bits; + + int long_rolling_target_bits; + int long_rolling_actual_bits; + + long long total_actual_bits; + int total_target_vs_actual; // debug stats + + int worst_quality; + int active_worst_quality; + int best_quality; + int active_best_quality; + + int drop_frames_allowed; // Are we permitted to drop frames? + int drop_frame; // Drop this frame? + int drop_count; // How many frames have we dropped? + int max_drop_count; // How many frames should we drop? + int max_consec_dropped_frames; // Limit number of consecutive frames that can be dropped. + + + int ymode_count [VP8_YMODES]; /* intra MB type cts this frame */ + int uv_mode_count[VP8_UV_MODES]; /* intra MB type cts this frame */ + + unsigned int MVcount [2] [MVvals]; /* (row,col) MV cts this frame */ + + unsigned int coef_counts [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens]; /* for this frame */ + //DECLARE_ALIGNED(16, int, coef_counts_backup [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens]); //not used any more + //save vp8_tree_probs_from_distribution result for each frame to avoid repeat calculation + vp8_prob frame_coef_probs [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1]; + unsigned int frame_branch_ct [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1][2]; + + /* Second compressed data partition contains coefficient data. */ + + unsigned char *output_partition2; + size_t output_partition2size; + + pre_proc_instance ppi; + + int frames_to_key; + int gfu_boost; + int kf_boost; + int last_boost; + double total_error_left; + double total_intra_error_left; + double total_coded_error_left; + double start_tot_err_left; + double min_error; + + double modified_total_error_left; + double avg_iiratio; + + int target_bandwidth; + long long bits_left; + FIRSTPASS_STATS total_stats; + FIRSTPASS_STATS this_frame_stats; + FIRSTPASS_STATS *stats_in, *stats_in_end; + struct vpx_codec_pkt_list *output_pkt_list; + int first_pass_done; + unsigned char *fp_motion_map; + FILE *fp_motion_mapfile; + int fpmm_pos; + +#if 0 + // Experimental code for lagged and one pass + ONEPASS_FRAMESTATS one_pass_frame_stats[MAX_LAG_BUFFERS]; + int one_pass_frame_index; +#endif + + int decimation_factor; + int decimation_count; + + // for real time encoding + int avg_encode_time; //microsecond + int avg_pick_mode_time; //microsecond + int Speed; + unsigned int cpu_freq; //Mhz + int compressor_speed; + + int interquantizer; + int auto_gold; + int auto_adjust_gold_quantizer; + int goldquantizer; + int goldfreq; + int auto_adjust_key_quantizer; + int keyquantizer; + int auto_worst_q; + int filter_type; + int cpu_used; + int chroma_boost; + int horiz_scale; + int vert_scale; + int pass; + + + int prob_intra_coded; + int prob_last_coded; + int prob_gf_coded; + int prob_skip_false; + int last_skip_false_probs[3]; + int last_skip_probs_q[3]; + int recent_ref_frame_usage[MAX_REF_FRAMES]; + + int count_mb_ref_frame_usage[MAX_REF_FRAMES]; + int this_frame_percent_intra; + int last_frame_percent_intra; + + int last_key_frame_q; + int last_kffilt_lvl; + + int ref_frame_flags; + + int exp[512]; + + SPEED_FEATURES sf; + int error_bins[1024]; + + int inter_lvl; + int intra_lvl; + int motion_lvl; + int motion_speed; + int motion_var; + int next_iiratio; + int this_iiratio; + int this_frame_modified_error; + + double norm_intra_err_per_mb; + double norm_inter_err_per_mb; + double norm_iidiff_per_mb; + + int last_best_mode_index; // Record of mode index chosen for previous macro block. + int last_auto_filt_val; + int last_auto_filt_q; + + // Data used for real time conferencing mode to help determine if it would be good to update the gf + int inter_zz_count; + int gf_bad_count; + int gf_update_recommended; + int skip_true_count; + int skip_false_count; + + int alt_qcount; + + int ready_for_new_frame; + + unsigned char *segmentation_map; + signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS]; // Segment data (can be deltas or absolute values) + int segment_encode_breakout[MAX_MB_SEGMENTS]; // segment threashold for encode breakout + + unsigned char *active_map; + unsigned int active_map_enabled; + // Video conferencing cyclic refresh mode flags etc + // This is a mode designed to clean up the background over time in live encoding scenarious. It uses segmentation + int cyclic_refresh_mode_enabled; + int cyclic_refresh_mode_max_mbs_perframe; + int cyclic_refresh_mode_index; + int cyclic_refresh_q; + signed char *cyclic_refresh_map; + + // multithread data + int current_mb_col_main; + int processor_core_count; + int b_multi_threaded; + int encoding_thread_count; + +#if CONFIG_MULTITHREAD + pthread_t *h_encoding_thread; +#endif + MB_ROW_COMP *mb_row_ei; + ENCODETHREAD_DATA *en_thread_data; + +#if CONFIG_MULTITHREAD + //events + sem_t *h_event_mbrencoding; + sem_t h_event_main; +#endif + + TOKENLIST *tplist; + // end of multithread data + + + fractional_mv_step_fp *find_fractional_mv_step; + vp8_full_search_fn_t full_search_sad; + vp8_diamond_search_fn_t diamond_search_sad; + vp8_variance_fn_ptr_t fn_ptr; + unsigned int time_receive_data; + unsigned int time_compress_data; + unsigned int time_pick_lpf; + unsigned int time_encode_mb_row; + + unsigned int tempdata1; + unsigned int tempdata2; + + int base_skip_false_prob[128]; + unsigned int section_is_low_motion; + unsigned int section_benefits_from_aggresive_q; + unsigned int section_is_fast_motion; + unsigned int section_intra_rating; + + double section_max_qfactor; + + +#if CONFIG_RUNTIME_CPU_DETECT + VP8_ENCODER_RTCD rtcd; +#endif +#if VP8_TEMPORAL_ALT_REF + SOURCE_SAMPLE alt_ref_buffer; + unsigned char *frames[MAX_LAG_BUFFERS]; + int fixed_divide[255]; +#endif + +#if CONFIG_PSNR + int count; + double total_y; + double total_u; + double total_v; + double total ; + double total_sq_error; + double totalp_y; + double totalp_u; + double totalp_v; + double totalp; + double total_sq_error2; + int bytes; + double summed_quality; + double summed_weights; + unsigned int tot_recode_hits; + + + double total_ssimg_y; + double total_ssimg_u; + double total_ssimg_v; + double total_ssimg_all; + + int b_calculate_ssimg; +#endif + int b_calculate_psnr; +} VP8_COMP; + +void control_data_rate(VP8_COMP *cpi); + +void vp8_encode_frame(VP8_COMP *cpi); + +void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size); + +int rd_cost_intra_mb(MACROBLOCKD *x); + +void vp8_tokenize_mb(VP8_COMP *, MACROBLOCKD *, TOKENEXTRA **); + +void vp8_set_speed_features(VP8_COMP *cpi); + +#if CONFIG_DEBUG +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval" at %s:%d", \ + __FILE__,__LINE__);\ + } while(0) +#else +#define CHECK_MEM_ERROR(lval,expr) do {\ + lval = (expr); \ + if(!lval) \ + vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,\ + "Failed to allocate "#lval);\ + } while(0) +#endif +#endif
diff --git a/vp8/encoder/parms.cpp b/vp8/encoder/parms.cpp new file mode 100644 index 0000000..66fdafb --- /dev/null +++ b/vp8/encoder/parms.cpp
@@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if 0 + +#include <map> +#include <string> +#include <fstream> +extern "C" +{ + #include "onyx.h" +} + + +using namespace std; + +typedef map<string,int> Parms; + +#define ALLPARMS(O,DOTHIS) \ + DOTHIS(O, interquantizer )\ + DOTHIS(O, auto_gold )\ + DOTHIS(O, auto_adjust_gold_quantizer )\ + DOTHIS(O, goldquantizer )\ + DOTHIS(O, goldfreq )\ + DOTHIS(O, auto_key )\ + DOTHIS(O, auto_adjust_key_quantizer )\ + DOTHIS(O, keyquantizer )\ + DOTHIS(O, keyfreq )\ + DOTHIS(O, pass )\ + DOTHIS(O, fixed_q )\ + DOTHIS(O, target_bandwidth )\ + DOTHIS(O, auto_worst_q )\ + DOTHIS(O, worst_quality )\ + DOTHIS(O, best_allowed_q )\ + DOTHIS(O, end_usage )\ + DOTHIS(O, starting_buffer_level )\ + DOTHIS(O, optimal_buffer_level )\ + DOTHIS(O, maximum_buffer_size )\ + DOTHIS(O, under_shoot_pct )\ + DOTHIS(O, allow_df )\ + DOTHIS(O, drop_frames_water_mark )\ + DOTHIS(O, max_allowed_datarate )\ + DOTHIS(O, two_pass_vbrbias )\ + DOTHIS(O, two_pass_vbrmin_section )\ + DOTHIS(O, two_pass_vbrmax_section )\ + DOTHIS(O, filter_type )\ + DOTHIS(O, compressor_speed )\ + DOTHIS(O, mbpitch_feature )\ + DOTHIS(O, allow_spatial_resampling )\ + DOTHIS(O, resample_down_water_mark )\ + DOTHIS(O, resample_up_water_mark )\ + DOTHIS(O, noise_sensitivity )\ + DOTHIS(O, horiz_scale )\ + DOTHIS(O, vert_scale ) + + +#define GET(O,V) O->V = x[#V]; +#define PUT(O,V) x[#V] = O->V; + + +extern "C" void get_parms(VP8_CONFIG *ocf,char *filename) +{ + + Parms x; + int value; + string variable; + string equal; + + ifstream config_file(filename); + + ALLPARMS(ocf, PUT); + + // store all the parms in a map (really simple parsing) + while(!config_file.eof() && config_file.is_open()) + { + config_file >> variable; + config_file >> equal; + + if(equal != "=") + continue; + + config_file >> value; + + x[variable] = value; + } + + ALLPARMS(ocf, GET); + +} + +#define PRINT(O,V) debug_file<<#V <<" = " << O->V <<"\n"; +extern "C" void print_parms(VP8_CONFIG *ocf,char *filename) +{ + ofstream debug_file(filename,ios_base::app); + ALLPARMS(ocf, PRINT); + debug_file << "=============================================="<<"\n"; +} + +#endif
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c new file mode 100644 index 0000000..d61e2ce --- /dev/null +++ b/vp8/encoder/pickinter.c
@@ -0,0 +1,923 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <limits.h> +#include "vpx_ports/config.h" +#include "onyx_int.h" +#include "modecosts.h" +#include "encodeintra.h" +#include "entropymode.h" +#include "pickinter.h" +#include "findnearmv.h" +#include "encodemb.h" +#include "reconinter.h" +#include "reconintra.h" +#include "reconintra4x4.h" +#include "g_common.h" +#include "variance.h" +#include "mcomp.h" + +#include "vpx_mem/vpx_mem.h" + +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif + +extern int VP8_UVSSE(MACROBLOCK *x, const vp8_variance_rtcd_vtable_t *rtcd); + +#ifdef SPEEDSTATS +extern unsigned int cnt_pm; +#endif + +extern const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES]; +extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; + + +extern unsigned int (*vp8_get16x16pred_error)(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +extern unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); +extern int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, MV *best_ref_mv, int best_rd, int *, int *, int *, int, int *mvcost[2], int, int fullpixel); +extern int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]); +extern void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, MV *mv); + + +int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, MV *bestmv, MV *ref_mv, int error_per_bit, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, int *mvcost[2]) +{ + (void) b; + (void) d; + (void) ref_mv; + (void) error_per_bit; + (void) svf; + (void) vf; + (void) mvcost; + bestmv->row <<= 3; + bestmv->col <<= 3; + return 0; +} + + +static int get_inter_mbpred_error(MACROBLOCK *mb, vp8_subpixvariance_fn_t svf, vp8_variance_fn_t vf, unsigned int *sse) +{ + + BLOCK *b = &mb->block[0]; + BLOCKD *d = &mb->e_mbd.block[0]; + unsigned char *what = (*(b->base_src) + b->src); + int what_stride = b->src_stride; + unsigned char *in_what = *(d->base_pre) + d->pre ; + int in_what_stride = d->pre_stride; + int xoffset = d->bmi.mv.as_mv.col & 7; + int yoffset = d->bmi.mv.as_mv.row & 7; + + in_what += (d->bmi.mv.as_mv.row >> 3) * d->pre_stride + (d->bmi.mv.as_mv.col >> 3); + + if (xoffset | yoffset) + { + return svf(in_what, in_what_stride, xoffset, yoffset, what, what_stride, sse); + } + else + { + return vf(what, what_stride, in_what, in_what_stride, sse); + } + +} + +unsigned int vp8_get16x16pred_error_c +( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad +) +{ + unsigned pred_error = 0; + int i, j; + int sum = 0; + + for (i = 0; i < 16; i++) + { + int diff; + + for (j = 0; j < 16; j++) + { + diff = src_ptr[j] - ref_ptr[j]; + sum += diff; + pred_error += diff * diff; + } + + src_ptr += src_stride; + ref_ptr += ref_stride; + } + + pred_error -= sum * sum / 256; + return pred_error; +} + + +unsigned int vp8_get4x4sse_cs_c +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + int max_sad +) +{ + int distortion = 0; + int r, c; + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int diff = src_ptr[c] - ref_ptr[c]; + distortion += diff * diff; + } + + src_ptr += source_stride; + ref_ptr += recon_stride; + } + + return distortion; +} + +static int get_prediction_error(BLOCK *be, BLOCKD *b, const vp8_variance_rtcd_vtable_t *rtcd) +{ + unsigned char *sptr; + unsigned char *dptr; + sptr = (*(be->base_src) + be->src); + dptr = b->predictor; + + return VARIANCE_INVOKE(rtcd, get4x4sse_cs)(sptr, be->src_stride, dptr, 16, 0x7fffffff); + +} + +static int pick_intra4x4block( + const VP8_ENCODER_RTCD *rtcd, + MACROBLOCK *x, + BLOCK *be, + BLOCKD *b, + B_PREDICTION_MODE *best_mode, + B_PREDICTION_MODE above, + B_PREDICTION_MODE left, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + + int *bestrate, + int *bestdistortion) +{ + B_PREDICTION_MODE mode; + int best_rd = INT_MAX; // 1<<30 + int rate; + int distortion; + unsigned int *mode_costs; + (void) l; + (void) a; + + if (x->e_mbd.frame_type == KEY_FRAME) + { + mode_costs = x->bmode_costs[above][left]; + } + else + { + mode_costs = x->inter_bmode_costs; + } + + for (mode = B_DC_PRED; mode <= B_HE_PRED /*B_HU_PRED*/; mode++) + { + int this_rd; + + rate = mode_costs[mode]; + vp8_predict_intra4x4(b, mode, b->predictor); + distortion = get_prediction_error(be, b, &rtcd->variance); + this_rd = RD_ESTIMATE(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + *bestrate = rate; + *bestdistortion = distortion; + best_rd = this_rd; + *best_mode = mode; + } + } + + b->bmi.mode = (B_PREDICTION_MODE)(*best_mode); + vp8_encode_intra4x4block(rtcd, x, be, b, b->bmi.mode); + return best_rd; +} + + +int vp8_pick_intra4x4mby_modes(const VP8_ENCODER_RTCD *rtcd, MACROBLOCK *mb, int *Rate, int *best_dist) +{ + MACROBLOCKD *const xd = &mb->e_mbd; + int i; + TEMP_CONTEXT t; + int cost = mb->mbmode_cost [xd->frame_type] [B_PRED]; + int error = RD_ESTIMATE(mb->rdmult, mb->rddiv, cost, 0); // Rd estimate for the cost of the block prediction mode + int distortion = 0; + + vp8_intra_prediction_down_copy(xd); + vp8_setup_temp_context(&t, xd->above_context[Y1CONTEXT], xd->left_context[Y1CONTEXT], 4); + + for (i = 0; i < 16; i++) + { + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + const B_PREDICTION_MODE A = vp8_above_bmi(mic, i, mis)->mode; + const B_PREDICTION_MODE L = vp8_left_bmi(mic, i)->mode; + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(d); + + error += pick_intra4x4block(rtcd, + mb, mb->block + i, xd->block + i, &best_mode, A, L, + t.a + vp8_block2above[i], + t.l + vp8_block2left[i], &r, &d); + + cost += r; + distortion += d; + + mic->bmi[i].mode = xd->block[i].bmi.mode = best_mode; + + // Break out case where we have already exceeded best so far value that was bassed in + if (distortion > *best_dist) + break; + } + + for (i = 0; i < 16; i++) + xd->block[i].bmi.mv.as_int = 0; + + *Rate = cost; + + if (i == 16) + *best_dist = distortion; + else + *best_dist = INT_MAX; + + + return error; +} + +int vp8_pick_intra_mbuv_mode(MACROBLOCK *mb) +{ + + MACROBLOCKD *x = &mb->e_mbd; + unsigned char *uabove_row = x->dst.u_buffer - x->dst.uv_stride; + unsigned char *vabove_row = x->dst.v_buffer - x->dst.uv_stride; + unsigned char *usrc_ptr = (mb->block[16].src + *mb->block[16].base_src); + unsigned char *vsrc_ptr = (mb->block[20].src + *mb->block[20].base_src); + int uvsrc_stride = mb->block[16].src_stride; + unsigned char uleft_col[8]; + unsigned char vleft_col[8]; + unsigned char utop_left = uabove_row[-1]; + unsigned char vtop_left = vabove_row[-1]; + int i, j; + int expected_udc; + int expected_vdc; + int shift; + int Uaverage = 0; + int Vaverage = 0; + int diff; + int pred_error[4] = {0, 0, 0, 0}, best_error = INT_MAX; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + + + for (i = 0; i < 8; i++) + { + uleft_col[i] = x->dst.u_buffer [i* x->dst.uv_stride -1]; + vleft_col[i] = x->dst.v_buffer [i* x->dst.uv_stride -1]; + } + + if (!x->up_available && !x->left_available) + { + expected_udc = 128; + expected_vdc = 128; + } + else + { + shift = 2; + + if (x->up_available) + { + + for (i = 0; i < 8; i++) + { + Uaverage += uabove_row[i]; + Vaverage += vabove_row[i]; + } + + shift ++; + + } + + if (x->left_available) + { + for (i = 0; i < 8; i++) + { + Uaverage += uleft_col[i]; + Vaverage += vleft_col[i]; + } + + shift ++; + + } + + expected_udc = (Uaverage + (1 << (shift - 1))) >> shift; + expected_vdc = (Vaverage + (1 << (shift - 1))) >> shift; + } + + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + + int predu = uleft_col[i] + uabove_row[j] - utop_left; + int predv = vleft_col[i] + vabove_row[j] - vtop_left; + int u_p, v_p; + + u_p = usrc_ptr[j]; + v_p = vsrc_ptr[j]; + + if (predu < 0) + predu = 0; + + if (predu > 255) + predu = 255; + + if (predv < 0) + predv = 0; + + if (predv > 255) + predv = 255; + + + diff = u_p - expected_udc; + pred_error[DC_PRED] += diff * diff; + diff = v_p - expected_vdc; + pred_error[DC_PRED] += diff * diff; + + + diff = u_p - uabove_row[j]; + pred_error[V_PRED] += diff * diff; + diff = v_p - vabove_row[j]; + pred_error[V_PRED] += diff * diff; + + + diff = u_p - uleft_col[i]; + pred_error[H_PRED] += diff * diff; + diff = v_p - vleft_col[i]; + pred_error[H_PRED] += diff * diff; + + + diff = u_p - predu; + pred_error[TM_PRED] += diff * diff; + diff = v_p - predv; + pred_error[TM_PRED] += diff * diff; + + + } + + usrc_ptr += uvsrc_stride; + vsrc_ptr += uvsrc_stride; + + if (i == 3) + { + usrc_ptr = (mb->block[18].src + *mb->block[18].base_src); + vsrc_ptr = (mb->block[22].src + *mb->block[22].base_src); + } + + + + } + + + for (i = DC_PRED; i <= TM_PRED; i++) + { + if (best_error > pred_error[i]) + { + best_error = pred_error[i]; + best_mode = (MB_PREDICTION_MODE)i; + } + } + + + mb->e_mbd.mbmi.uv_mode = best_mode; + return best_error; + +} + + +int vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra) +{ + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MACROBLOCKD *xd = &x->e_mbd; + B_MODE_INFO best_bmodes[16]; + MB_MODE_INFO best_mbmode; + MV best_ref_mv1; + MV mode_mv[MB_MODE_COUNT]; + MB_PREDICTION_MODE this_mode; + int num00; + int i; + int mdcounts[4]; + int best_rd = INT_MAX; // 1 << 30; + int best_intra_rd = INT_MAX; + int mode_index; + int ref_frame_cost[MAX_REF_FRAMES]; + int rate; + int rate2; + int distortion2; + int bestsme; + //int all_rds[MAX_MODES]; // Experimental debug code. + int best_mode_index = 0; + int sse = INT_MAX; + + MV nearest_mv[4]; + MV near_mv[4]; + MV best_ref_mv[4]; + int MDCounts[4][4]; + unsigned char *y_buffer[4]; + unsigned char *u_buffer[4]; + unsigned char *v_buffer[4]; + + int skip_mode[4] = {0, 0, 0, 0}; + + vpx_memset(mode_mv, 0, sizeof(mode_mv)); + vpx_memset(nearest_mv, 0, sizeof(nearest_mv)); + vpx_memset(near_mv, 0, sizeof(near_mv)); + + + // set up all the refframe dependent pointers. + if (cpi->ref_frame_flags & VP8_LAST_FLAG) + { + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[LAST_FRAME], &near_mv[LAST_FRAME], + &best_ref_mv[LAST_FRAME], MDCounts[LAST_FRAME], LAST_FRAME, cpi->common.ref_frame_sign_bias); + + y_buffer[LAST_FRAME] = cpi->common.last_frame.y_buffer + recon_yoffset; + u_buffer[LAST_FRAME] = cpi->common.last_frame.u_buffer + recon_uvoffset; + v_buffer[LAST_FRAME] = cpi->common.last_frame.v_buffer + recon_uvoffset; + } + else + skip_mode[LAST_FRAME] = 1; + + if (cpi->ref_frame_flags & VP8_GOLD_FLAG) + { + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[GOLDEN_FRAME], &near_mv[GOLDEN_FRAME], + &best_ref_mv[GOLDEN_FRAME], MDCounts[GOLDEN_FRAME], GOLDEN_FRAME, cpi->common.ref_frame_sign_bias); + + y_buffer[GOLDEN_FRAME] = cpi->common.golden_frame.y_buffer + recon_yoffset; + u_buffer[GOLDEN_FRAME] = cpi->common.golden_frame.u_buffer + recon_uvoffset; + v_buffer[GOLDEN_FRAME] = cpi->common.golden_frame.v_buffer + recon_uvoffset; + } + else + skip_mode[GOLDEN_FRAME] = 1; + + if (cpi->ref_frame_flags & VP8_ALT_FLAG && cpi->source_alt_ref_active) + { + vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, &nearest_mv[ALTREF_FRAME], &near_mv[ALTREF_FRAME], + &best_ref_mv[ALTREF_FRAME], MDCounts[ALTREF_FRAME], ALTREF_FRAME, cpi->common.ref_frame_sign_bias); + + y_buffer[ALTREF_FRAME] = cpi->common.alt_ref_frame.y_buffer + recon_yoffset; + u_buffer[ALTREF_FRAME] = cpi->common.alt_ref_frame.u_buffer + recon_uvoffset; + v_buffer[ALTREF_FRAME] = cpi->common.alt_ref_frame.v_buffer + recon_uvoffset; + } + else + skip_mode[ALTREF_FRAME] = 1; + + cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame + + *returnintra = best_intra_rd; + x->skip = 0; + + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); + + // Special case treatment when GF and ARF are not sensible options for reference + if (cpi->ref_frame_flags == VP8_LAST_FLAG) + { + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_zero(255); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(255) + + vp8_cost_zero(128); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(255) + + vp8_cost_one(128); + } + else + { + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_zero(cpi->prob_last_coded); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_zero(cpi->prob_gf_coded); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_one(cpi->prob_gf_coded); + } + + + + best_rd = INT_MAX; + + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + + // if we encode a new mv this is important + // find the best new motion vector + for (mode_index = 0; mode_index < MAX_MODES; mode_index++) + { + int frame_cost; + int this_rd = INT_MAX; + + if (best_rd <= cpi->rd_threshes[mode_index]) + continue; + + x->e_mbd.mbmi.ref_frame = vp8_ref_frame_order[mode_index]; + + if (skip_mode[x->e_mbd.mbmi.ref_frame]) + continue; + + // Check to see if the testing frequency for this mode is at its max + // If so then prevent it from being tested and increase the threshold for its testing + if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) + { + //if ( (cpi->mbs_tested_so_far / cpi->mode_test_hit_counts[mode_index]) <= cpi->mode_check_freq[mode_index] ) + if (cpi->mbs_tested_so_far <= (cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index])) + { + // Increase the threshold for coding this mode to make it less likely to be chosen + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + + continue; + } + } + + // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested + cpi->mode_test_hit_counts[mode_index] ++; + + rate2 = 0; + distortion2 = 0; + + this_mode = vp8_mode_order[mode_index]; + + // Experimental debug code. + //all_rds[mode_index] = -1; + + x->e_mbd.mbmi.mode = this_mode; + x->e_mbd.mbmi.uv_mode = DC_PRED; + + // Work out the cost assosciated with selecting the reference frame + frame_cost = ref_frame_cost[x->e_mbd.mbmi.ref_frame]; + rate2 += frame_cost; + + // everything but intra + if (x->e_mbd.mbmi.ref_frame) + { + x->e_mbd.pre.y_buffer = y_buffer[x->e_mbd.mbmi.ref_frame]; + x->e_mbd.pre.u_buffer = u_buffer[x->e_mbd.mbmi.ref_frame]; + x->e_mbd.pre.v_buffer = v_buffer[x->e_mbd.mbmi.ref_frame]; + mode_mv[NEARESTMV] = nearest_mv[x->e_mbd.mbmi.ref_frame]; + mode_mv[NEARMV] = near_mv[x->e_mbd.mbmi.ref_frame]; + best_ref_mv1 = best_ref_mv[x->e_mbd.mbmi.ref_frame]; + memcpy(mdcounts, MDCounts[x->e_mbd.mbmi.ref_frame], sizeof(mdcounts)); + } + + //Only consider ZEROMV/ALTREF_FRAME for alt ref frame. + if (cpi->is_src_frame_alt_ref) + { + if (this_mode != ZEROMV || x->e_mbd.mbmi.ref_frame != ALTREF_FRAME) + continue; + } + + switch (this_mode) + { + case B_PRED: + distortion2 = *returndistortion; // Best so far passed in as breakout value to vp8_pick_intra4x4mby_modes + vp8_pick_intra4x4mby_modes(IF_RTCD(&cpi->rtcd), x, &rate, &distortion2); + rate2 += rate; + distortion2 = VARIANCE_INVOKE(&cpi->rtcd.variance, get16x16prederror)(x->src.y_buffer, x->src.y_stride, x->e_mbd.predictor, 16, 0x7fffffff); + + if (distortion2 == INT_MAX) + { + this_rd = INT_MAX; + } + else + { + this_rd = RD_ESTIMATE(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_intra_rd) + { + best_intra_rd = this_rd; + *returnintra = best_intra_rd ; + } + } + + break; + + case SPLITMV: + + // Split MV modes currently not supported when RD is nopt enabled. + break; + + case DC_PRED: + case V_PRED: + case H_PRED: + case TM_PRED: + vp8_build_intra_predictors_mby_ptr(&x->e_mbd); + distortion2 = VARIANCE_INVOKE(&cpi->rtcd.variance, get16x16prederror)(x->src.y_buffer, x->src.y_stride, x->e_mbd.predictor, 16, 0x7fffffff); + rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mbmi.mode]; + this_rd = RD_ESTIMATE(x->rdmult, x->rddiv, rate2, distortion2); + + if (this_rd < best_intra_rd) + { + best_intra_rd = this_rd; + *returnintra = best_intra_rd ; + } + + break; + + case NEWMV: + { + int thissme; + int step_param; + int further_steps; + int n = 0; + int sadpb = x->sadperbit16; + + // Further step/diamond searches as necessary + if (cpi->Speed < 8) + { + step_param = cpi->sf.first_step + ((cpi->Speed > 5) ? 1 : 0); + further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + } + else + { + step_param = cpi->sf.first_step + 2; + further_steps = 0; + } + +#if 0 + + // Initial step Search + bestsme = vp8_diamond_search_sad(x, b, d, &best_ref_mv1, &d->bmi.mv.as_mv, step_param, x->errorperbit, &num00, &cpi->fn_ptr, cpi->mb.mvsadcost, cpi->mb.mvcost); + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + + // Further step searches + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = vp8_diamond_search_sad(x, b, d, &best_ref_mv1, &d->bmi.mv.as_mv, step_param + n, x->errorperbit, &num00, &cpi->fn_ptr, cpi->mb.mvsadcost, x->mvcost); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + } + else + { + d->bmi.mv.as_mv.row = mode_mv[NEWMV].row; + d->bmi.mv.as_mv.col = mode_mv[NEWMV].col; + } + } + } + +#else + + if (cpi->sf.search_method == HEX) + { + bestsme = vp8_hex_search(x, b, d, &best_ref_mv1, &d->bmi.mv.as_mv, step_param, sadpb/*x->errorperbit*/, &num00, cpi->fn_ptr.vf, cpi->fn_ptr.sdf, x->mvsadcost, x->mvcost); + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + } + else + { + bestsme = cpi->diamond_search_sad(x, b, d, &best_ref_mv1, &d->bmi.mv.as_mv, step_param, sadpb / 2/*x->errorperbit*/, &num00, &cpi->fn_ptr, x->mvsadcost, x->mvcost); //sadpb < 9 + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + + // Further step/diamond searches as necessary + n = 0; + //further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = cpi->diamond_search_sad(x, b, d, &best_ref_mv1, &d->bmi.mv.as_mv, step_param + n, sadpb / 4/*x->errorperbit*/, &num00, &cpi->fn_ptr, x->mvsadcost, x->mvcost); //sadpb = 9 + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + } + else + { + d->bmi.mv.as_mv.row = mode_mv[NEWMV].row; + d->bmi.mv.as_mv.col = mode_mv[NEWMV].col; + } + } + } + } + +#endif + } + + if (bestsme < INT_MAX) + cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv.as_mv, &best_ref_mv1, x->errorperbit, cpi->fn_ptr.svf, cpi->fn_ptr.vf, cpi->mb.mvcost); + + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + + // mv cost; + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv1, cpi->mb.mvcost, 128); + + + case NEARESTMV: + case NEARMV: + + if (mode_mv[this_mode].row == 0 && mode_mv[this_mode].col == 0) + continue; + + case ZEROMV: + + // Trap vectors that reach beyond the UMV borders + // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point + // because of the lack of break statements in the previous two cases. + if (((mode_mv[this_mode].row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].col >> 3) > x->mv_col_max)) + continue; + + rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + x->e_mbd.mbmi.mode = this_mode; + x->e_mbd.mbmi.mv.as_mv = mode_mv[this_mode]; + x->e_mbd.block[0].bmi.mode = this_mode; + x->e_mbd.block[0].bmi.mv.as_int = x->e_mbd.mbmi.mv.as_int; + + distortion2 = get_inter_mbpred_error(x, cpi->fn_ptr.svf, cpi->fn_ptr.vf, (unsigned int *)(&sse)); + + this_rd = RD_ESTIMATE(x->rdmult, x->rddiv, rate2, distortion2); + + if (cpi->active_map_enabled && x->active_ptr[0] == 0) + { + x->skip = 1; + } + else if (sse < x->encode_breakout) + { + // Check u and v to make sure skip is ok + int sse2 = 0; + + sse2 = VP8_UVSSE(x, IF_RTCD(&cpi->rtcd.variance)); + + if (sse2 * 2 < x->encode_breakout) + x->skip = 1; + else + x->skip = 0; + } + + break; + default: + break; + } + + // Experimental debug code. + //all_rds[mode_index] = this_rd; + + if (this_rd < best_rd || x->skip) + { + // Note index of best mode + best_mode_index = mode_index; + + *returnrate = rate2; + *returndistortion = distortion2; + best_rd = this_rd; + vpx_memcpy(&best_mbmode, &x->e_mbd.mbmi, sizeof(MB_MODE_INFO)); + + if (this_mode == B_PRED || this_mode == SPLITMV) + for (i = 0; i < 16; i++) + { + vpx_memcpy(&best_bmodes[i], &x->e_mbd.block[i].bmi, sizeof(B_MODE_INFO)); + } + else + { + best_bmodes[0].mv = x->e_mbd.block[0].bmi.mv; + } + + // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time + cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + // If the mode did not help improve the best error case then raise the threshold for testing that mode next time around. + else + { + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + if (x->skip) + break; + } + + // Reduce the activation RD thresholds for the best choice mode + if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) + { + int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 3); + + cpi->rd_thresh_mult[best_mode_index] = (cpi->rd_thresh_mult[best_mode_index] >= (MIN_THRESHMULT + best_adjustment)) ? cpi->rd_thresh_mult[best_mode_index] - best_adjustment : MIN_THRESHMULT; + cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; + } + + // Keep a record of best mode index for use in next loop + cpi->last_best_mode_index = best_mode_index; + + if (best_mbmode.mode <= B_PRED) + { + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + vp8_pick_intra_mbuv_mode(x); + best_mbmode.uv_mode = x->e_mbd.mbmi.uv_mode; + } + + + { + int this_rdbin = (*returndistortion >> 7); + + if (this_rdbin >= 1024) + { + this_rdbin = 1023; + } + + cpi->error_bins[this_rdbin] ++; + } + + + if (cpi->is_src_frame_alt_ref && (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) + { + best_mbmode.mode = ZEROMV; + best_mbmode.ref_frame = ALTREF_FRAME; + best_mbmode.mv.as_int = 0; + best_mbmode.uv_mode = 0; + best_mbmode.mb_skip_coeff = (cpi->common.mb_no_coeff_skip) ? 1 : 0; + best_mbmode.partitioning = 0; + best_mbmode.dc_diff = 0; + + vpx_memcpy(&x->e_mbd.mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + + for (i = 0; i < 16; i++) + { + vpx_memset(&x->e_mbd.block[i].bmi, 0, sizeof(B_MODE_INFO)); + } + + x->e_mbd.mbmi.mv.as_int = 0; + + return best_rd; + } + + + // macroblock modes + vpx_memcpy(&x->e_mbd.mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + + if (x->e_mbd.mbmi.mode == B_PRED || x->e_mbd.mbmi.mode == SPLITMV) + for (i = 0; i < 16; i++) + { + vpx_memcpy(&x->e_mbd.block[i].bmi, &best_bmodes[i], sizeof(B_MODE_INFO)); + + } + else + { + vp8_set_mbmode_and_mvs(x, x->e_mbd.mbmi.mode, &best_bmodes[0].mv.as_mv); + } + + x->e_mbd.mbmi.mv.as_mv = x->e_mbd.block[15].bmi.mv.as_mv; + + return best_rd; +}
diff --git a/vp8/encoder/pickinter.h b/vp8/encoder/pickinter.h new file mode 100644 index 0000000..fb28837 --- /dev/null +++ b/vp8/encoder/pickinter.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_PICKINTER_H +#define __INC_PICKINTER_H +#include "vpx_ports/config.h" +#include "onyxc_int.h" + +#define RD_ESTIMATE(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) +extern int vp8_pick_intra4x4mby_modes(const VP8_ENCODER_RTCD *, MACROBLOCK *mb, int *Rate, int *Distortion); +extern int vp8_pick_intra_mbuv_mode(MACROBLOCK *mb); +extern int vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); +#endif
diff --git a/vp8/encoder/picklpf.c b/vp8/encoder/picklpf.c new file mode 100644 index 0000000..bbd7840 --- /dev/null +++ b/vp8/encoder/picklpf.c
@@ -0,0 +1,435 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "onyxc_int.h" +#include "onyx_int.h" +#include "quantize.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_scale/yv12extend.h" +#include "vpx_scale/vpxscale.h" +#include "alloccommon.h" + +extern void vp8_loop_filter_frame(VP8_COMMON *cm, MACROBLOCKD *mbd, int filt_val); +extern void vp8_loop_filter_frame_yonly(VP8_COMMON *cm, MACROBLOCKD *mbd, int filt_val, int sharpness_lvl); +extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, const vp8_variance_rtcd_vtable_t *rtcd); +#if HAVE_ARMV7 +extern void vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc); +#endif + +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif + +extern void +(*vp8_yv12_copy_partial_frame_ptr)(YV12_BUFFER_CONFIG *src_ybc, + YV12_BUFFER_CONFIG *dst_ybc, + int Fraction); +void +vp8_yv12_copy_partial_frame(YV12_BUFFER_CONFIG *src_ybc, YV12_BUFFER_CONFIG *dst_ybc, int Fraction) +{ + unsigned char *src_y, *dst_y; + int yheight; + int ystride; + int border; + int yoffset; + int linestocopy; + + border = src_ybc->border; + yheight = src_ybc->y_height; + ystride = src_ybc->y_stride; + + linestocopy = (yheight >> (Fraction + 4)); + + if (linestocopy < 1) + linestocopy = 1; + + linestocopy <<= 4; + + yoffset = ystride * ((yheight >> 5) * 16 - 8); + src_y = src_ybc->y_buffer + yoffset; + dst_y = dst_ybc->y_buffer + yoffset; + + vpx_memcpy(dst_y, src_y, ystride *(linestocopy + 16)); +} + +static int vp8_calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, int Fraction, const vp8_variance_rtcd_vtable_t *rtcd) +{ + int i, j; + int Total = 0; + int srcoffset, dstoffset; + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + + int linestocopy = (source->y_height >> (Fraction + 4)); + (void)rtcd; + + if (linestocopy < 1) + linestocopy = 1; + + linestocopy <<= 4; + + + srcoffset = source->y_stride * (dest->y_height >> 5) * 16; + dstoffset = dest->y_stride * (dest->y_height >> 5) * 16; + + src += srcoffset; + dst += dstoffset; + + // Loop through the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < linestocopy; i += 16) + { + for (j = 0; j < source->y_width; j += 16) + { + unsigned int sse; + Total += VARIANCE_INVOKE(rtcd, mse16x16)(src + j, source->y_stride, dst + j, dest->y_stride, &sse); + } + + src += 16 * source->y_stride; + dst += 16 * dest->y_stride; + } + + return Total; +} + +extern void vp8_loop_filter_partial_frame +( + VP8_COMMON *cm, + MACROBLOCKD *mbd, + int default_filt_lvl, + int sharpness_lvl, + int Fraction +); + +// Enforce a minimum filter level based upon baseline Q +static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) +{ + int min_filter_level; + + if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame && !cpi->common.refresh_alt_ref_frame) + min_filter_level = 0; + else + { + if (base_qindex <= 6) + min_filter_level = 0; + else if (base_qindex <= 16) + min_filter_level = 1; + else + min_filter_level = (base_qindex / 8); + } + + return min_filter_level; +} + +// Enforce a maximum filter level based upon baseline Q +static int get_max_filter_level(VP8_COMP *cpi, int base_qindex) +{ + // PGW August 2006: Highest filter values almost always a bad idea + + // jbb chg: 20100118 - not so any more with this overquant stuff allow high values + // with lots of intra coming in. + int max_filter_level = MAX_LOOP_FILTER ;//* 3 / 4; + + if (cpi->section_intra_rating > 8) + max_filter_level = MAX_LOOP_FILTER * 3 / 4; + + (void) cpi; + (void) base_qindex; + + return max_filter_level; +} + +void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int best_err = 0; + int filt_err = 0; + int min_filter_level = 0; + int max_filter_level = MAX_LOOP_FILTER * 3 / 4; // PGW August 2006: Highest filter values almost always a bad idea + int filt_val; + int best_filt_val = cm->filter_level; + + // Make a copy of the unfiltered / processed recon buffer + //vp8_yv12_copy_frame_ptr( cm->frame_to_show, &cpi->last_frame_uf ); + vp8_yv12_copy_partial_frame_ptr(cm->frame_to_show, &cpi->last_frame_uf, 3); + + if (cm->frame_type == KEY_FRAME) + cm->sharpness_level = 0; + else + cm->sharpness_level = cpi->oxcf.Sharpness; + + // Enforce a minimum filter level based upon Q + min_filter_level = get_min_filter_level(cpi, cm->base_qindex); + max_filter_level = get_max_filter_level(cpi, cm->base_qindex); + + // Start the search at the previous frame filter level unless it is now out of range. + if (cm->filter_level < min_filter_level) + cm->filter_level = min_filter_level; + else if (cm->filter_level > max_filter_level) + cm->filter_level = max_filter_level; + + filt_val = cm->filter_level; + best_filt_val = filt_val; + + // Set up alternate filter values + + // Get the err using the previous frame's filter value. + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0 , 3); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + best_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame + vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3); + + filt_val -= (1 + ((filt_val > 10) ? 1 : 0)); + + // Search lower filter levels + while (filt_val >= min_filter_level) + { + // Apply the loop filter + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0, 3); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + // Get the err for filtered frame + filt_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance)); + + + // Re-instate the unfiltered frame + vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3); + + + // Update the best case record or exit loop. + if (filt_err < best_err) + { + best_err = filt_err; + best_filt_val = filt_val; + } + else + break; + + // Adjust filter level + filt_val -= (1 + ((filt_val > 10) ? 1 : 0)); + } + + // Search up (note that we have already done filt_val = cm->filter_level) + filt_val = cm->filter_level + (1 + ((filt_val > 10) ? 1 : 0)); + + if (best_filt_val == cm->filter_level) + { + // Resist raising filter level for very small gains + best_err -= (best_err >> 10); + + while (filt_val < max_filter_level) + { + // Apply the loop filter + vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val, 0, 3); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + // Get the err for filtered frame + filt_err = vp8_calc_partial_ssl_err(sd, cm->frame_to_show, 3, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame + vp8_yv12_copy_partial_frame_ptr(&cpi->last_frame_uf, cm->frame_to_show, 3); + + // Update the best case record or exit loop. + if (filt_err < best_err) + { + // Do not raise filter level if improvement is < 1 part in 4096 + best_err = filt_err - (filt_err >> 10); + + best_filt_val = filt_val; + } + else + break; + + // Adjust filter level + filt_val += (1 + ((filt_val > 10) ? 1 : 0)); + } + } + + cm->filter_level = best_filt_val; + + if (cm->filter_level < min_filter_level) + cm->filter_level = min_filter_level; + + if (cm->filter_level > max_filter_level) + cm->filter_level = max_filter_level; +} + +// Stub function for now Alt LF not used +void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) +{ + MACROBLOCKD *mbd = &cpi->mb.e_mbd; + (void) filt_val; + + mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0]; + mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1]; + mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2]; + mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3]; +} + +void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) +{ + VP8_COMMON *cm = &cpi->common; + + int best_err = 0; + int filt_err = 0; + int min_filter_level; + int max_filter_level; + int prediction_difference = (int)(100 * abs((int)(cpi->last_auto_filter_prediction_error - cpi->prediction_error)) / (1 + cpi->prediction_error)); + + int filter_step; + int filt_high = 0; + int filt_mid = cm->filter_level; // Start search at previous frame filter level + int filt_low = 0; + int filt_best; + int filt_direction = 0; + + int Bias = 0; // Bias against raising loop filter and in favour of lowering it + + // Make a copy of the unfiltered / processed recon buffer +#if HAVE_ARMV7 + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(cm->frame_to_show, &cpi->last_frame_uf); +#else + vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cpi->last_frame_uf); +#endif + + if (cm->frame_type == KEY_FRAME) + cm->sharpness_level = 0; + else + cm->sharpness_level = cpi->oxcf.Sharpness; + + // Enforce a minimum filter level based upon Q + min_filter_level = get_min_filter_level(cpi, cm->base_qindex); + max_filter_level = get_max_filter_level(cpi, cm->base_qindex); + + // Start the search at the previous frame filter level unless it is now out of range. + filt_mid = cm->filter_level; + + if (filt_mid < min_filter_level) + filt_mid = min_filter_level; + else if (filt_mid > max_filter_level) + filt_mid = max_filter_level; + + // Define the initial step size + filter_step = (filt_mid < 16) ? 4 : filt_mid / 4; + + // Get baseline error score + vp8cx_set_alt_lf_level(cpi, filt_mid); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid, 0); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + best_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + filt_best = filt_mid; + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); +#else + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); +#endif + + while (filter_step > 0) + { + Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; //PGW change 12/12/06 for small images + + // jbb chg: 20100118 - in sections with lots of new material coming in don't bias as much to a low filter value + if (cpi->section_intra_rating < 20) + Bias = Bias * cpi->section_intra_rating / 20; + + filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step); + filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step); + + if ((filt_direction <= 0) && (filt_low != filt_mid)) + { + // Get Low filter error score + vp8cx_set_alt_lf_level(cpi, filt_low); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low, 0); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); +#else + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); +#endif + + // If value is close to the best so far then bias towards a lower loop filter value. + if ((filt_err - Bias) < best_err) + { + // Was it actually better than the previous best? + if (filt_err < best_err) + best_err = filt_err; + + filt_best = filt_low; + } + } + + // Now look at filt_high + if ((filt_direction >= 0) && (filt_high != filt_mid)) + { + vp8cx_set_alt_lf_level(cpi, filt_high); + vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high, 0); + cm->last_frame_type = cm->frame_type; + cm->last_filter_type = cm->filter_type; + cm->last_sharpness_level = cm->sharpness_level; + + filt_err = vp8_calc_ss_err(sd, cm->frame_to_show, IF_RTCD(&cpi->rtcd.variance)); + + // Re-instate the unfiltered frame +#if HAVE_ARMV7 + vp8_yv12_copy_frame_yonly_no_extend_frame_borders_neon(&cpi->last_frame_uf, cm->frame_to_show); +#else + vp8_yv12_copy_frame_yonly_ptr(&cpi->last_frame_uf, cm->frame_to_show); +#endif + + // Was it better than the previous best? + if (filt_err < (best_err - Bias)) + { + best_err = filt_err; + filt_best = filt_high; + } + } + + // Half the step distance if the best filter value was the same as last time + if (filt_best == filt_mid) + { + filter_step = filter_step / 2; + filt_direction = 0; + } + else + { + filt_direction = (filt_best < filt_mid) ? -1 : 1; + filt_mid = filt_best; + } + } + + cm->filter_level = filt_best; + cpi->last_auto_filt_val = filt_best; + cpi->last_auto_filt_q = cm->base_qindex; + + cpi->last_auto_filter_prediction_error = cpi->prediction_error; + cpi->frames_since_auto_filter = 0; +}
diff --git a/vp8/encoder/ppc/csystemdependent.c b/vp8/encoder/ppc/csystemdependent.c new file mode 100644 index 0000000..f99277f --- /dev/null +++ b/vp8/encoder/ppc/csystemdependent.c
@@ -0,0 +1,168 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "variance.h" +#include "onyx_int.h" + +SADFunction *vp8_sad16x16; +SADFunction *vp8_sad16x8; +SADFunction *vp8_sad8x16; +SADFunction *vp8_sad8x8; +SADFunction *vp8_sad4x4; + +variance_function *vp8_variance4x4; +variance_function *vp8_variance8x8; +variance_function *vp8_variance8x16; +variance_function *vp8_variance16x8; +variance_function *vp8_variance16x16; + +variance_function *vp8_mse16x16; + +sub_pixel_variance_function *vp8_sub_pixel_variance4x4; +sub_pixel_variance_function *vp8_sub_pixel_variance8x8; +sub_pixel_variance_function *vp8_sub_pixel_variance8x16; +sub_pixel_variance_function *vp8_sub_pixel_variance16x8; +sub_pixel_variance_function *vp8_sub_pixel_variance16x16; + +int (*vp8_block_error)(short *coeff, short *dqcoeff); +int (*vp8_mbblock_error)(MACROBLOCK *mb, int dc); + +int (*vp8_mbuverror)(MACROBLOCK *mb); +unsigned int (*vp8_get_mb_ss)(short *); +void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct8x4)(short *input, short *output, int pitch); +void (*short_walsh4x4)(short *input, short *output, int pitch); + +void (*vp8_subtract_b)(BLOCK *be, BLOCKD *bd, int pitch); +void (*vp8_subtract_mby)(short *diff, unsigned char *src, unsigned char *pred, int stride); +void (*vp8_subtract_mbuv)(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +void (*vp8_fast_quantize_b)(BLOCK *b, BLOCKD *d); + +unsigned int (*vp8_get16x16pred_error)(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +unsigned int (*vp8_get8x8var)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +unsigned int (*vp8_get16x16var)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// c imports +extern int block_error_c(short *coeff, short *dqcoeff); +extern int vp8_mbblock_error_c(MACROBLOCK *mb, int dc); + +extern int vp8_mbuverror_c(MACROBLOCK *mb); +extern unsigned int vp8_get8x8var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern void short_fdct4x4_c(short *input, short *output, int pitch); +extern void short_fdct8x4_c(short *input, short *output, int pitch); +extern void vp8_short_walsh4x4_c(short *input, short *output, int pitch); + +extern void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch); +extern void subtract_mby_c(short *diff, unsigned char *src, unsigned char *pred, int stride); +extern void subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +extern void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d); + +extern SADFunction sad16x16_c; +extern SADFunction sad16x8_c; +extern SADFunction sad8x16_c; +extern SADFunction sad8x8_c; +extern SADFunction sad4x4_c; + +extern variance_function variance16x16_c; +extern variance_function variance8x16_c; +extern variance_function variance16x8_c; +extern variance_function variance8x8_c; +extern variance_function variance4x4_c; +extern variance_function mse16x16_c; + +extern sub_pixel_variance_function sub_pixel_variance4x4_c; +extern sub_pixel_variance_function sub_pixel_variance8x8_c; +extern sub_pixel_variance_function sub_pixel_variance8x16_c; +extern sub_pixel_variance_function sub_pixel_variance16x8_c; +extern sub_pixel_variance_function sub_pixel_variance16x16_c; + +extern unsigned int vp8_get_mb_ss_c(short *); +extern unsigned int vp8_get16x16pred_error_c(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +extern unsigned int vp8_get8x8var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get4x4sse_cs_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// ppc +extern int vp8_block_error_ppc(short *coeff, short *dqcoeff); + +extern void vp8_short_fdct4x4_ppc(short *input, short *output, int pitch); +extern void vp8_short_fdct8x4_ppc(short *input, short *output, int pitch); + +extern void vp8_subtract_mby_ppc(short *diff, unsigned char *src, unsigned char *pred, int stride); +extern void vp8_subtract_mbuv_ppc(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); + +extern SADFunction vp8_sad16x16_ppc; +extern SADFunction vp8_sad16x8_ppc; +extern SADFunction vp8_sad8x16_ppc; +extern SADFunction vp8_sad8x8_ppc; +extern SADFunction vp8_sad4x4_ppc; + +extern variance_function vp8_variance16x16_ppc; +extern variance_function vp8_variance8x16_ppc; +extern variance_function vp8_variance16x8_ppc; +extern variance_function vp8_variance8x8_ppc; +extern variance_function vp8_variance4x4_ppc; +extern variance_function vp8_mse16x16_ppc; + +extern sub_pixel_variance_function vp8_sub_pixel_variance4x4_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x8_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x16_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x8_ppc; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x16_ppc; + +extern unsigned int vp8_get8x8var_ppc(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_ppc(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); + +void vp8_cmachine_specific_config(void) +{ + // Pure C: + vp8_mbuverror = vp8_mbuverror_c; + vp8_fast_quantize_b = vp8_fast_quantize_b_c; + vp8_short_fdct4x4 = vp8_short_fdct4x4_ppc; + vp8_short_fdct8x4 = vp8_short_fdct8x4_ppc; + vp8_fast_fdct4x4 = vp8_short_fdct4x4_ppc; + vp8_fast_fdct8x4 = vp8_short_fdct8x4_ppc; + short_walsh4x4 = vp8_short_walsh4x4_c; + + vp8_variance4x4 = vp8_variance4x4_ppc; + vp8_variance8x8 = vp8_variance8x8_ppc; + vp8_variance8x16 = vp8_variance8x16_ppc; + vp8_variance16x8 = vp8_variance16x8_ppc; + vp8_variance16x16 = vp8_variance16x16_ppc; + vp8_mse16x16 = vp8_mse16x16_ppc; + + vp8_sub_pixel_variance4x4 = vp8_sub_pixel_variance4x4_ppc; + vp8_sub_pixel_variance8x8 = vp8_sub_pixel_variance8x8_ppc; + vp8_sub_pixel_variance8x16 = vp8_sub_pixel_variance8x16_ppc; + vp8_sub_pixel_variance16x8 = vp8_sub_pixel_variance16x8_ppc; + vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_ppc; + + vp8_get_mb_ss = vp8_get_mb_ss_c; + vp8_get16x16pred_error = vp8_get16x16pred_error_c; + vp8_get8x8var = vp8_get8x8var_ppc; + vp8_get16x16var = vp8_get16x16var_ppc; + vp8_get4x4sse_cs = vp8_get4x4sse_cs_c; + + vp8_sad16x16 = vp8_sad16x16_ppc; + vp8_sad16x8 = vp8_sad16x8_ppc; + vp8_sad8x16 = vp8_sad8x16_ppc; + vp8_sad8x8 = vp8_sad8x8_ppc; + vp8_sad4x4 = vp8_sad4x4_ppc; + + vp8_block_error = vp8_block_error_ppc; + vp8_mbblock_error = vp8_mbblock_error_c; + + vp8_subtract_b = vp8_subtract_b_c; + vp8_subtract_mby = vp8_subtract_mby_ppc; + vp8_subtract_mbuv = vp8_subtract_mbuv_ppc; +}
diff --git a/vp8/encoder/ppc/encodemb_altivec.asm b/vp8/encoder/ppc/encodemb_altivec.asm new file mode 100644 index 0000000..e0e976d --- /dev/null +++ b/vp8/encoder/ppc/encodemb_altivec.asm
@@ -0,0 +1,152 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_subtract_mbuv_ppc + .globl vp8_subtract_mby_ppc + +;# r3 short *diff +;# r4 unsigned char *usrc +;# r5 unsigned char *vsrc +;# r6 unsigned char *pred +;# r7 int stride +vp8_subtract_mbuv_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf000 + mtspr 256, r12 ;# set VRSAVE + + li r9, 256 + add r3, r3, r9 + add r3, r3, r9 + add r6, r6, r9 + + li r10, 16 + li r9, 4 + mtctr r9 + + vspltisw v0, 0 + +mbu_loop: + lvsl v5, 0, r4 ;# permutate value for alignment + lvx v1, 0, r4 ;# src + lvx v2, 0, r6 ;# pred + + add r4, r4, r7 + addi r6, r6, 16 + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + lvsl v5, 0, r4 ;# permutate value for alignment + lvx v1, 0, r4 ;# src + + add r4, r4, r7 + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrglb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mbu_loop + + mtctr r9 + +mbv_loop: + lvsl v5, 0, r5 ;# permutate value for alignment + lvx v1, 0, r5 ;# src + lvx v2, 0, r6 ;# pred + + add r5, r5, r7 + addi r6, r6, 16 + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + lvsl v5, 0, r5 ;# permutate value for alignment + lvx v1, 0, r5 ;# src + + add r5, r5, r7 + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vperm v1, v1, v0, v5 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrglb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mbv_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr + +;# r3 short *diff +;# r4 unsigned char *src +;# r5 unsigned char *pred +;# r6 int stride +vp8_subtract_mby_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf800 + mtspr 256, r12 ;# set VRSAVE + + li r10, 16 + mtctr r10 + + vspltisw v0, 0 + +mby_loop: + lvx v1, 0, r4 ;# src + lvx v2, 0, r5 ;# pred + + add r4, r4, r6 + addi r5, r5, 16 + + vmrghb v3, v0, v1 ;# unpack high src to short + vmrghb v4, v0, v2 ;# unpack high pred to short + + vsubshs v3, v3, v4 + + stvx v3, 0, r3 ;# store out diff + + vmrglb v3, v0, v1 ;# unpack low src to short + vmrglb v4, v0, v2 ;# unpack low pred to short + + vsubshs v3, v3, v4 + + stvx v3, r10, r3 ;# store out diff + + addi r3, r3, 32 + + bdnz mby_loop + + mtspr 256, r11 ;# reset old VRSAVE + + blr
diff --git a/vp8/encoder/ppc/fdct_altivec.asm b/vp8/encoder/ppc/fdct_altivec.asm new file mode 100644 index 0000000..eaab14c --- /dev/null +++ b/vp8/encoder/ppc/fdct_altivec.asm
@@ -0,0 +1,204 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_short_fdct4x4_ppc + .globl vp8_short_fdct8x4_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +;# Forward and inverse DCTs are nearly identical; only differences are +;# in normalization (fwd is twice unitary, inv is half unitary) +;# and that they are of course transposes of each other. +;# +;# The following three accomplish most of implementation and +;# are used only by ppc_idct.c and ppc_fdct.c. +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfffc + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + li r6, 16 + + load_c v0, dct_tab, 0, r9, r10 + lvx v1, r6, r10 + addi r10, r10, 32 + lvx v2, 0, r10 + lvx v3, r6, r10 + + load_c v4, ppc_dctperm_tab, 0, r9, r10 + load_c v5, ppc_dctperm_tab, r6, r9, r10 + + load_c v6, round_tab, 0, r10, r9 +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +;# Do horiz xf on two rows of coeffs v8 = a0 a1 a2 a3 b0 b1 b2 b3. +;# a/A are the even rows 0,2 b/B are the odd rows 1,3 +;# For fwd transform, indices are horizontal positions, then frequencies. +;# For inverse transform, frequencies then positions. +;# The two resulting A0..A3 B0..B3 are later combined +;# and vertically transformed. + +.macro two_rows_horiz Dst + vperm v9, v8, v8, v4 ;# v9 = a2 a3 a0 a1 b2 b3 b0 b1 + + vmsumshm v10, v0, v8, v6 + vmsumshm v10, v1, v9, v10 + vsraw v10, v10, v7 ;# v10 = A0 A1 B0 B1 + + vmsumshm v11, v2, v8, v6 + vmsumshm v11, v3, v9, v11 + vsraw v11, v11, v7 ;# v11 = A2 A3 B2 B3 + + vpkuwum v10, v10, v11 ;# v10 = A0 A1 B0 B1 A2 A3 B2 B3 + vperm \Dst, v10, v10, v5 ;# Dest = A0 B0 A1 B1 A2 B2 A3 B3 +.endm + +;# Vertical xf on two rows. DCT values in comments are for inverse transform; +;# forward transform uses transpose. + +.macro two_rows_vert Ceven, Codd + vspltw v8, \Ceven, 0 ;# v8 = c00 c10 or c02 c12 four times + vspltw v9, \Codd, 0 ;# v9 = c20 c30 or c22 c32 "" + vmsumshm v8, v8, v12, v6 + vmsumshm v8, v9, v13, v8 + vsraw v10, v8, v7 + + vspltw v8, \Codd, 1 ;# v8 = c01 c11 or c03 c13 + vspltw v9, \Ceven, 1 ;# v9 = c21 c31 or c23 c33 + vmsumshm v8, v8, v12, v6 + vmsumshm v8, v9, v13, v8 + vsraw v8, v8, v7 + + vpkuwum v8, v10, v8 ;# v8 = rows 0,1 or 2,3 +.endm + +.macro two_rows_h Dest + stw r0, 0(r8) + lwz r0, 4(r3) + stw r0, 4(r8) + lwzux r0, r3,r5 + stw r0, 8(r8) + lwz r0, 4(r3) + stw r0, 12(r8) + lvx v8, 0,r8 + two_rows_horiz \Dest +.endm + + .align 2 +;# r3 short *input +;# r4 short *output +;# r5 int pitch +vp8_short_fdct4x4_ppc: + + prologue + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + epilogue + + blr + + .align 2 +;# r3 short *input +;# r4 short *output +;# r5 int pitch +vp8_short_fdct8x4_ppc: + prologue + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + addi r10, r3, 0 + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + ;# Next block + addi r3, r10, 8 + addi r4, r4, 32 + lvx v6, 0, r9 ;# v6 = Hround + + vspltisw v7, 14 ;# == 14, fits in 5 signed bits + addi r8, r1, 0 + + lwz r0, 0(r3) + two_rows_h v12 ;# v12 = H00 H10 H01 H11 H02 H12 H03 H13 + + lwzux r0, r3, r5 + two_rows_h v13 ;# v13 = H20 H30 H21 H31 H22 H32 H23 H33 + + lvx v6, r6, r9 ;# v6 = Vround + vspltisw v7, -16 ;# == 16 == -16, only low 5 bits matter + + two_rows_vert v0, v1 + stvx v8, 0, r4 + two_rows_vert v2, v3 + stvx v8, r6, r4 + + epilogue + + blr + + .data + .align 4 +ppc_dctperm_tab: + .byte 4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11 + .byte 0,1,4,5, 2,3,6,7, 8,9,12,13, 10,11,14,15 + + .align 4 +dct_tab: + .short 23170, 23170,-12540,-30274, 23170, 23170,-12540,-30274 + .short 23170, 23170, 30274, 12540, 23170, 23170, 30274, 12540 + + .short 23170,-23170, 30274,-12540, 23170,-23170, 30274,-12540 + .short -23170, 23170, 12540,-30274,-23170, 23170, 12540,-30274 + + .align 4 +round_tab: + .long (1 << (14-1)), (1 << (14-1)), (1 << (14-1)), (1 << (14-1)) + .long (1 << (16-1)), (1 << (16-1)), (1 << (16-1)), (1 << (16-1))
diff --git a/vp8/encoder/ppc/rdopt_altivec.asm b/vp8/encoder/ppc/rdopt_altivec.asm new file mode 100644 index 0000000..917bfe0 --- /dev/null +++ b/vp8/encoder/ppc/rdopt_altivec.asm
@@ -0,0 +1,50 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_block_error_ppc + + .align 2 +;# r3 short *Coeff +;# r4 short *dqcoeff +vp8_block_error_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf800 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + stw r5, 12(r1) ;# tranfer dc to vector register + + lvx v0, 0, r3 ;# Coeff + lvx v1, 0, r4 ;# dqcoeff + + li r10, 16 + + vspltisw v3, 0 + + vsubshs v0, v0, v1 + + vmsumshm v2, v0, v0, v3 ;# multiply differences + + lvx v0, r10, r3 ;# Coeff + lvx v1, r10, r4 ;# dqcoeff + + vsubshs v0, v0, v1 + + vmsumshm v1, v0, v0, v2 ;# multiply differences + vsumsws v1, v1, v3 ;# sum up + + stvx v1, 0, r1 + lwz r3, 12(r1) ;# return value + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr
diff --git a/vp8/encoder/ppc/sad_altivec.asm b/vp8/encoder/ppc/sad_altivec.asm new file mode 100644 index 0000000..1102ccf --- /dev/null +++ b/vp8/encoder/ppc/sad_altivec.asm
@@ -0,0 +1,276 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_sad16x16_ppc + .globl vp8_sad16x8_ppc + .globl vp8_sad8x16_ppc + .globl vp8_sad8x8_ppc + .globl vp8_sad4x4_ppc + +.macro load_aligned_16 V R O + lvsl v3, 0, \R ;# permutate value for alignment + + lvx v1, 0, \R + lvx v2, \O, \R + + vperm \V, v1, v2, v3 +.endm + +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + li r10, 16 ;# load offset and loop counter + + vspltisw v8, 0 ;# zero out total to start +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +.macro SAD_16 + ;# v6 = abs (v4 - v5) + vsububs v6, v4, v5 + vsububs v7, v5, v4 + vor v6, v6, v7 + + ;# v8 += abs (v4 - v5) + vsum4ubs v8, v6, v8 +.endm + +.macro sad_16_loop loop_label + lvsl v3, 0, r5 ;# only needs to be done once per block + + ;# preload a line of data before getting into the loop + lvx v4, 0, r3 + lvx v1, 0, r5 + lvx v2, r10, r5 + + add r5, r5, r6 + add r3, r3, r4 + + vperm v5, v1, v2, v3 + + .align 4 +\loop_label: + ;# compute difference on first row + vsububs v6, v4, v5 + vsububs v7, v5, v4 + + ;# load up next set of data + lvx v9, 0, r3 + lvx v1, 0, r5 + lvx v2, r10, r5 + + ;# perform abs() of difference + vor v6, v6, v7 + add r3, r3, r4 + + ;# add to the running tally + vsum4ubs v8, v6, v8 + + ;# now onto the next line + vperm v5, v1, v2, v3 + add r5, r5, r6 + lvx v4, 0, r3 + + ;# compute difference on second row + vsububs v6, v9, v5 + lvx v1, 0, r5 + vsububs v7, v5, v9 + lvx v2, r10, r5 + vor v6, v6, v7 + add r3, r3, r4 + vsum4ubs v8, v6, v8 + vperm v5, v1, v2, v3 + add r5, r5, r6 + + bdnz \loop_label + + vspltisw v7, 0 + + vsumsws v8, v8, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) +.endm + +.macro sad_8_loop loop_label + .align 4 +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# only one of the inputs should need to be aligned. + load_aligned_16 v6, r3, r10 + load_aligned_16 v7, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + vmrghb v4, v4, v6 + vmrghb v5, v5, v7 + + SAD_16 + + bdnz \loop_label + + vspltisw v7, 0 + + vsumsws v8, v8, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad16x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + sad_16_loop sad16x16_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad16x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + sad_16_loop sad16x8_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad8x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + sad_8_loop sad8x16_loop + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad8x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + sad_8_loop sad8x8_loop + + epilogue + + blr + +.macro transfer_4x4 I P + lwz r0, 0(\I) + add \I, \I, \P + + lwz r7, 0(\I) + add \I, \I, \P + + lwz r8, 0(\I) + add \I, \I, \P + + lwz r9, 0(\I) + + stw r0, 0(r1) + stw r7, 4(r1) + stw r8, 8(r1) + stw r9, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_stride +;# r5 unsigned char *ref_ptr +;# r6 int ref_stride +;# +;# r3 return value +vp8_sad4x4_ppc: + + prologue + + transfer_4x4 r3, r4 + lvx v4, 0, r1 + + transfer_4x4 r5, r6 + lvx v5, 0, r1 + + vspltisw v8, 0 ;# zero out total to start + + ;# v6 = abs (v4 - v5) + vsububs v6, v4, v5 + vsububs v7, v5, v4 + vor v6, v6, v7 + + ;# v8 += abs (v4 - v5) + vsum4ubs v7, v6, v8 + vsumsws v7, v7, v8 + + stvx v7, 0, r1 + lwz r3, 12(r1) + + epilogue + + blr
diff --git a/vp8/encoder/ppc/variance_altivec.asm b/vp8/encoder/ppc/variance_altivec.asm new file mode 100644 index 0000000..952bf72 --- /dev/null +++ b/vp8/encoder/ppc/variance_altivec.asm
@@ -0,0 +1,374 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_get8x8var_ppc + .globl vp8_get16x16var_ppc + .globl vp8_mse16x16_ppc + .globl vp8_variance16x16_ppc + .globl vp8_variance16x8_ppc + .globl vp8_variance8x16_ppc + .globl vp8_variance8x8_ppc + .globl vp8_variance4x4_ppc + +.macro load_aligned_16 V R O + lvsl v3, 0, \R ;# permutate value for alignment + + lvx v1, 0, \R + lvx v2, \O, \R + + vperm \V, v1, v2, v3 +.endm + +.macro prologue + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffc0 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + li r10, 16 ;# load offset and loop counter + + vspltisw v7, 0 ;# zero for merging + vspltisw v8, 0 ;# zero out total to start + vspltisw v9, 0 ;# zero out total for dif^2 +.endm + +.macro epilogue + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE +.endm + +.macro compute_sum_sse + ;# Compute sum first. Unpack to so signed subract + ;# can be used. Only have a half word signed + ;# subract. Do high, then low. + vmrghb v2, v7, v4 + vmrghb v3, v7, v5 + vsubshs v2, v2, v3 + vsum4shs v8, v2, v8 + + vmrglb v2, v7, v4 + vmrglb v3, v7, v5 + vsubshs v2, v2, v3 + vsum4shs v8, v2, v8 + + ;# Now compute sse. + vsububs v2, v4, v5 + vsububs v3, v5, v4 + vor v2, v2, v3 + + vmsumubm v9, v2, v2, v9 +.endm + +.macro variance_16 DS loop_label store_sum +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + compute_sum_sse + + bdnz \loop_label + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + +.if \store_sum + stw r3, 0(r8) ;# sum +.endif + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srawi r3, r3, \DS ;# (sum*sum) >> DS + subf r3, r3, r4 ;# sse - ((sum*sum) >> DS) +.endm + +.macro variance_8 DS loop_label store_sum +\loop_label: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# only one of the inputs should need to be aligned. + load_aligned_16 v6, r3, r10 + load_aligned_16 v0, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + vmrghb v4, v4, v6 + vmrghb v5, v5, v0 + + compute_sum_sse + + bdnz \loop_label + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + +.if \store_sum + stw r3, 0(r8) ;# sum +.endif + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srawi r3, r3, \DS ;# (sum*sum) >> 8 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 8) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *SSE +;# r8 int *Sum +;# +;# r3 return value +vp8_get8x8var_ppc: + + prologue + + li r9, 4 + mtctr r9 + + variance_8 6, get8x8var_loop, 1 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *SSE +;# r8 int *Sum +;# +;# r3 return value +vp8_get16x16var_ppc: + + prologue + + mtctr r10 + + variance_16 8, get16x16var_loop, 1 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r 3 return value +vp8_mse16x16_ppc: + prologue + + mtctr r10 + +mse16x16_loop: + ;# only one of the inputs should need to be aligned. + load_aligned_16 v4, r3, r10 + load_aligned_16 v5, r5, r10 + + ;# move onto the next line + add r3, r3, r4 + add r5, r5, r6 + + ;# Now compute sse. + vsububs v2, v4, v5 + vsububs v3, v5, v4 + vor v2, v2, v3 + + vmsumubm v9, v2, v2, v9 + + bdnz mse16x16_loop + + vsumsws v9, v9, v7 + + stvx v9, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r3, 12(r1) + + stw r3, 0(r7) ;# sse + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance16x16_ppc: + + prologue + + mtctr r10 + + variance_16 8, variance16x16_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance16x8_ppc: + + prologue + + li r9, 8 + mtctr r9 + + variance_16 7, variance16x8_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance8x16_ppc: + + prologue + + li r9, 8 + mtctr r9 + + variance_8 7, variance8x16_loop, 0 + + epilogue + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance8x8_ppc: + + prologue + + li r9, 4 + mtctr r9 + + variance_8 6, variance8x8_loop, 0 + + epilogue + + blr + +.macro transfer_4x4 I P + lwz r0, 0(\I) + add \I, \I, \P + + lwz r10,0(\I) + add \I, \I, \P + + lwz r8, 0(\I) + add \I, \I, \P + + lwz r9, 0(\I) + + stw r0, 0(r1) + stw r10, 4(r1) + stw r8, 8(r1) + stw r9, 12(r1) +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int source_stride +;# r5 unsigned char *ref_ptr +;# r6 int recon_stride +;# r7 unsigned int *sse +;# +;# r3 return value +vp8_variance4x4_ppc: + + prologue + + transfer_4x4 r3, r4 + lvx v4, 0, r1 + + transfer_4x4 r5, r6 + lvx v5, 0, r1 + + compute_sum_sse + + vsumsws v8, v8, v7 + vsumsws v9, v9, v7 + + stvx v8, 0, r1 + lwz r3, 12(r1) + + stvx v9, 0, r1 + lwz r4, 12(r1) + + stw r4, 0(r7) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srawi r3, r3, 4 ;# (sum*sum) >> 4 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 4) + + epilogue + + blr
diff --git a/vp8/encoder/ppc/variance_subpixel_altivec.asm b/vp8/encoder/ppc/variance_subpixel_altivec.asm new file mode 100644 index 0000000..148a8d2 --- /dev/null +++ b/vp8/encoder/ppc/variance_subpixel_altivec.asm
@@ -0,0 +1,864 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + + .globl vp8_sub_pixel_variance4x4_ppc + .globl vp8_sub_pixel_variance8x8_ppc + .globl vp8_sub_pixel_variance8x16_ppc + .globl vp8_sub_pixel_variance16x8_ppc + .globl vp8_sub_pixel_variance16x16_ppc + +.macro load_c V, LABEL, OFF, R0, R1 + lis \R0, \LABEL@ha + la \R1, \LABEL@l(\R0) + lvx \V, \OFF, \R1 +.endm + +.macro load_vfilter V0, V1 + load_c \V0, vfilter_b, r6, r12, r10 + + addi r6, r6, 16 + lvx \V1, r6, r10 +.endm + +.macro HProlog jump_label + ;# load up horizontal filter + slwi. r5, r5, 4 ;# index into horizontal filter array + + ;# index to the next set of vectors in the row. + li r10, 16 + + ;# downshift by 7 ( divide by 128 ) at the end + vspltish v19, 7 + + ;# If there isn't any filtering to be done for the horizontal, then + ;# just skip to the second pass. + beq \jump_label + + load_c v20, hfilter_b, r5, r12, r0 + + ;# setup constants + ;# v14 permutation value for alignment + load_c v28, b_hperm_b, 0, r12, r0 + + ;# index to the next set of vectors in the row. + li r12, 32 + + ;# rounding added in on the multiply + vspltisw v21, 8 + vspltisw v18, 3 + vslw v18, v21, v18 ;# 0x00000040000000400000004000000040 + + slwi. r6, r6, 5 ;# index into vertical filter array +.endm + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# + +.macro hfilter_8 V, hp, lp, increment_counter + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 9 bytes wide, output is 8 bytes. + lvx v21, 0, r3 + lvx v22, r10, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + + vperm v24, v21, v21, \hp ;# v20 = 0123 1234 2345 3456 + vperm v25, v21, v21, \lp ;# v21 = 4567 5678 6789 789A + + vmsummbm v24, v20, v24, v18 + vmsummbm v25, v20, v25, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + + vpkuhus \V, v24, v24 ;# \V = scrambled 8-bit result +.endm + +.macro vfilter_16 P0 P1 + vmuleub v22, \P0, v20 ;# 64 + 4 positive taps + vadduhm v22, v18, v22 + vmuloub v23, \P0, v20 + vadduhm v23, v18, v23 + + vmuleub v24, \P1, v21 + vadduhm v22, v22, v24 ;# Re = evens, saturation unnecessary + vmuloub v25, \P1, v21 + vadduhm v23, v23, v25 ;# Ro = odds + + vsrh v22, v22, v19 ;# divide by 128 + vsrh v23, v23, v19 ;# v16 v17 = evens, odds + vmrghh \P0, v22, v23 ;# v18 v19 = 16-bit result in order + vmrglh v23, v22, v23 + vpkuhus \P0, \P0, v23 ;# P0 = 8-bit result +.endm + +.macro compute_sum_sse src, ref, sum, sse, t1, t2, z0 + ;# Compute sum first. Unpack to so signed subract + ;# can be used. Only have a half word signed + ;# subract. Do high, then low. + vmrghb \t1, \z0, \src + vmrghb \t2, \z0, \ref + vsubshs \t1, \t1, \t2 + vsum4shs \sum, \t1, \sum + + vmrglb \t1, \z0, \src + vmrglb \t2, \z0, \ref + vsubshs \t1, \t1, \t2 + vsum4shs \sum, \t1, \sum + + ;# Now compute sse. + vsububs \t1, \src, \ref + vsububs \t2, \ref, \src + vor \t1, \t1, \t2 + + vmsumubm \sse, \t1, \t1, \sse +.endm + +.macro variance_final sum, sse, z0, DS + vsumsws \sum, \sum, \z0 + vsumsws \sse, \sse, \z0 + + stvx \sum, 0, r1 + lwz r3, 12(r1) + + stvx \sse, 0, r1 + lwz r4, 12(r1) + + stw r4, 0(r9) ;# sse + + mullw r3, r3, r3 ;# sum*sum + srawi r3, r3, \DS ;# (sum*sum) >> 8 + subf r3, r3, r4 ;# sse - ((sum*sum) >> 8) +.endm + +.macro compute_sum_sse_16 V, increment_counter + load_and_align_16 v16, r7, r8, \increment_counter + compute_sum_sse \V, v16, v18, v19, v20, v21, v23 +.endm + +.macro load_and_align_16 V, R, P, increment_counter + lvsl v17, 0, \R ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, \R + lvx v22, r10, \R + +.if \increment_counter + add \R, \R, \P +.endif + + vperm \V, v21, v22, v17 +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance4x4_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xf830 + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_4x4_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r12, r0 + load_c v11, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v10, v11, 1 + hfilter_8 v1, v10, v11, 1 + hfilter_8 v2, v10, v11, 1 + hfilter_8 v3, v10, v11, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_4x4_b + + hfilter_8 v4, v10, v11, 0 + + b second_pass_4x4_b + +second_pass_4x4_pre_copy_b: + slwi r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 0 + +second_pass_4x4_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + +compute_sum_sse_4x4_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + load_and_align_16 v4, r7, r8, 1 + load_and_align_16 v5, r7, r8, 1 + load_and_align_16 v6, r7, r8, 1 + load_and_align_16 v7, r7, r8, 1 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + + load_c v10, b_hilo_b, 0, r12, r0 + + vperm v0, v0, v1, v10 + vperm v1, v2, v3, v10 + + compute_sum_sse v0, v1, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 4 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance8x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xfff0 + ori r12, r12, 0xffff + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x8_pre_copy_b + + ;# Load up permutation constants + load_c v10, b_0123_b, 0, r12, r0 + load_c v11, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v10, v11, 1 + hfilter_8 v1, v10, v11, 1 + hfilter_8 v2, v10, v11, 1 + hfilter_8 v3, v10, v11, 1 + hfilter_8 v4, v10, v11, 1 + hfilter_8 v5, v10, v11, 1 + hfilter_8 v6, v10, v11, 1 + hfilter_8 v7, v10, v11, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_8x8_b + + hfilter_8 v8, v10, v11, 0 + + b second_pass_8x8_b + +second_pass_8x8_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 0 + + beq compute_sum_sse_8x8_b + +second_pass_8x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +compute_sum_sse_8x8_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + + load_and_align_16 v4, r7, r8, 1 + load_and_align_16 v5, r7, r8, 1 + load_and_align_16 v6, r7, r8, 1 + load_and_align_16 v7, r7, r8, 1 + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 0 + + vmrghb v4, v4, v5 + vmrghb v5, v6, v7 + vmrghb v6, v8, v9 + vmrghb v7, v10, v11 + + compute_sum_sse v0, v4, v18, v19, v20, v21, v23 + compute_sum_sse v1, v5, v18, v19, v20, v21, v23 + compute_sum_sse v2, v6, v18, v19, v20, v21, v23 + compute_sum_sse v3, v7, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 6 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance8x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfffc + mtspr 256, r12 ;# set VRSAVE + + stwu r1,-32(r1) ;# create space on the stack + + HProlog second_pass_8x16_pre_copy_b + + ;# Load up permutation constants + load_c v29, b_0123_b, 0, r12, r0 + load_c v30, b_4567_b, 0, r12, r0 + + hfilter_8 v0, v29, v30, 1 + hfilter_8 v1, v29, v30, 1 + hfilter_8 v2, v29, v30, 1 + hfilter_8 v3, v29, v30, 1 + hfilter_8 v4, v29, v30, 1 + hfilter_8 v5, v29, v30, 1 + hfilter_8 v6, v29, v30, 1 + hfilter_8 v7, v29, v30, 1 + hfilter_8 v8, v29, v30, 1 + hfilter_8 v9, v29, v30, 1 + hfilter_8 v10, v29, v30, 1 + hfilter_8 v11, v29, v30, 1 + hfilter_8 v12, v29, v30, 1 + hfilter_8 v13, v29, v30, 1 + hfilter_8 v14, v29, v30, 1 + hfilter_8 v15, v29, v30, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_8x16_b + + hfilter_8 v16, v29, v30, 0 + + b second_pass_8x16_b + +second_pass_8x16_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + load_and_align_16 v9, r3, r4, 1 + load_and_align_16 v10, r3, r4, 1 + load_and_align_16 v11, r3, r4, 1 + load_and_align_16 v12, r3, r4, 1 + load_and_align_16 v13, r3, r4, 1 + load_and_align_16 v14, r3, r4, 1 + load_and_align_16 v15, r3, r4, 1 + load_and_align_16 v16, r3, r4, 0 + + beq compute_sum_sse_8x16_b + +second_pass_8x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +compute_sum_sse_8x16_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + vmrghb v0, v0, v1 + vmrghb v1, v2, v3 + vmrghb v2, v4, v5 + vmrghb v3, v6, v7 + vmrghb v4, v8, v9 + vmrghb v5, v10, v11 + vmrghb v6, v12, v13 + vmrghb v7, v14, v15 + + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 1 + load_and_align_16 v12, r7, r8, 1 + load_and_align_16 v13, r7, r8, 1 + load_and_align_16 v14, r7, r8, 1 + load_and_align_16 v15, r7, r8, 1 + + vmrghb v8, v8, v9 + vmrghb v9, v10, v11 + vmrghb v10, v12, v13 + vmrghb v11, v14, v15 + + compute_sum_sse v0, v8, v18, v19, v20, v21, v23 + compute_sum_sse v1, v9, v18, v19, v20, v21, v23 + compute_sum_sse v2, v10, v18, v19, v20, v21, v23 + compute_sum_sse v3, v11, v18, v19, v20, v21, v23 + + load_and_align_16 v8, r7, r8, 1 + load_and_align_16 v9, r7, r8, 1 + load_and_align_16 v10, r7, r8, 1 + load_and_align_16 v11, r7, r8, 1 + load_and_align_16 v12, r7, r8, 1 + load_and_align_16 v13, r7, r8, 1 + load_and_align_16 v14, r7, r8, 1 + load_and_align_16 v15, r7, r8, 0 + + vmrghb v8, v8, v9 + vmrghb v9, v10, v11 + vmrghb v10, v12, v13 + vmrghb v11, v14, v15 + + compute_sum_sse v4, v8, v18, v19, v20, v21, v23 + compute_sum_sse v5, v9, v18, v19, v20, v21, v23 + compute_sum_sse v6, v10, v18, v19, v20, v21, v23 + compute_sum_sse v7, v11, v18, v19, v20, v21, v23 + + variance_final v18, v19, v23, 7 + + addi r1, r1, 32 ;# recover stack + mtspr 256, r11 ;# reset old VRSAVE + blr + +;# Filters a horizontal line +;# expects: +;# r3 src_ptr +;# r4 pitch +;# r10 16 +;# r12 32 +;# v17 perm intput +;# v18 rounding +;# v19 shift +;# v20 filter taps +;# v21 tmp +;# v22 tmp +;# v23 tmp +;# v24 tmp +;# v25 tmp +;# v26 tmp +;# v27 tmp +;# v28 perm output +;# +.macro hfilter_16 V, increment_counter + + lvsl v17, 0, r3 ;# permutate value for alignment + + ;# input to filter is 21 bytes wide, output is 16 bytes. + ;# input will can span three vectors if not aligned correctly. + lvx v21, 0, r3 + lvx v22, r10, r3 + lvx v23, r12, r3 + +.if \increment_counter + add r3, r3, r4 +.endif + vperm v21, v21, v22, v17 + vperm v22, v22, v23, v17 ;# v8 v9 = 21 input pixels left-justified + + ;# set 0 + vmsummbm v24, v20, v21, v18 ;# taps times elements + + ;# set 1 + vsldoi v23, v21, v22, 1 + vmsummbm v25, v20, v23, v18 + + ;# set 2 + vsldoi v23, v21, v22, 2 + vmsummbm v26, v20, v23, v18 + + ;# set 3 + vsldoi v23, v21, v22, 3 + vmsummbm v27, v20, v23, v18 + + vpkswus v24, v24, v25 ;# v24 = 0 4 8 C 1 5 9 D (16-bit) + vpkswus v25, v26, v27 ;# v25 = 2 6 A E 3 7 B F + + vsrh v24, v24, v19 ;# divide v0, v1 by 128 + vsrh v25, v25, v19 + + vpkuhus \V, v24, v25 ;# \V = scrambled 8-bit result + vperm \V, \V, v0, v28 ;# \V = correctly-ordered result +.endm + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance16x8_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + HProlog second_pass_16x8_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_16x8_b + + hfilter_16 v8, 0 + + b second_pass_16x8_b + +second_pass_16x8_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + + beq compute_sum_sse_16x8_b + +second_pass_16x8_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + +compute_sum_sse_16x8_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + compute_sum_sse_16 v0, 1 + compute_sum_sse_16 v1, 1 + compute_sum_sse_16 v2, 1 + compute_sum_sse_16 v3, 1 + compute_sum_sse_16 v4, 1 + compute_sum_sse_16 v5, 1 + compute_sum_sse_16 v6, 1 + compute_sum_sse_16 v7, 0 + + variance_final v18, v19, v23, 7 + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .align 2 +;# r3 unsigned char *src_ptr +;# r4 int src_pixels_per_line +;# r5 int xoffset +;# r6 int yoffset +;# r7 unsigned char *dst_ptr +;# r8 int dst_pixels_per_line +;# r9 unsigned int *sse +;# +;# r3 return value +vp8_sub_pixel_variance16x16_ppc: + mfspr r11, 256 ;# get old VRSAVE + oris r12, r11, 0xffff + ori r12, r12, 0xfff8 + mtspr 256, r12 ;# set VRSAVE + + stwu r1, -32(r1) ;# create space on the stack + + HProlog second_pass_16x16_pre_copy_b + + hfilter_16 v0, 1 + hfilter_16 v1, 1 + hfilter_16 v2, 1 + hfilter_16 v3, 1 + hfilter_16 v4, 1 + hfilter_16 v5, 1 + hfilter_16 v6, 1 + hfilter_16 v7, 1 + hfilter_16 v8, 1 + hfilter_16 v9, 1 + hfilter_16 v10, 1 + hfilter_16 v11, 1 + hfilter_16 v12, 1 + hfilter_16 v13, 1 + hfilter_16 v14, 1 + hfilter_16 v15, 1 + + ;# Finished filtering main horizontal block. If there is no + ;# vertical filtering, jump to storing the data. Otherwise + ;# load up and filter the additional line that is needed + ;# for the vertical filter. + beq compute_sum_sse_16x16_b + + hfilter_16 v16, 0 + + b second_pass_16x16_b + +second_pass_16x16_pre_copy_b: + slwi. r6, r6, 5 ;# index into vertical filter array + + load_and_align_16 v0, r3, r4, 1 + load_and_align_16 v1, r3, r4, 1 + load_and_align_16 v2, r3, r4, 1 + load_and_align_16 v3, r3, r4, 1 + load_and_align_16 v4, r3, r4, 1 + load_and_align_16 v5, r3, r4, 1 + load_and_align_16 v6, r3, r4, 1 + load_and_align_16 v7, r3, r4, 1 + load_and_align_16 v8, r3, r4, 1 + load_and_align_16 v9, r3, r4, 1 + load_and_align_16 v10, r3, r4, 1 + load_and_align_16 v11, r3, r4, 1 + load_and_align_16 v12, r3, r4, 1 + load_and_align_16 v13, r3, r4, 1 + load_and_align_16 v14, r3, r4, 1 + load_and_align_16 v15, r3, r4, 1 + load_and_align_16 v16, r3, r4, 0 + + beq compute_sum_sse_16x16_b + +second_pass_16x16_b: + vspltish v20, 8 + vspltish v18, 3 + vslh v18, v20, v18 ;# 0x0040 0040 0040 0040 0040 0040 0040 0040 + + load_vfilter v20, v21 + + vfilter_16 v0, v1 + vfilter_16 v1, v2 + vfilter_16 v2, v3 + vfilter_16 v3, v4 + vfilter_16 v4, v5 + vfilter_16 v5, v6 + vfilter_16 v6, v7 + vfilter_16 v7, v8 + vfilter_16 v8, v9 + vfilter_16 v9, v10 + vfilter_16 v10, v11 + vfilter_16 v11, v12 + vfilter_16 v12, v13 + vfilter_16 v13, v14 + vfilter_16 v14, v15 + vfilter_16 v15, v16 + +compute_sum_sse_16x16_b: + vspltish v18, 0 ;# sum + vspltish v19, 0 ;# sse + vspltish v23, 0 ;# unpack + li r10, 16 + + compute_sum_sse_16 v0, 1 + compute_sum_sse_16 v1, 1 + compute_sum_sse_16 v2, 1 + compute_sum_sse_16 v3, 1 + compute_sum_sse_16 v4, 1 + compute_sum_sse_16 v5, 1 + compute_sum_sse_16 v6, 1 + compute_sum_sse_16 v7, 1 + compute_sum_sse_16 v8, 1 + compute_sum_sse_16 v9, 1 + compute_sum_sse_16 v10, 1 + compute_sum_sse_16 v11, 1 + compute_sum_sse_16 v12, 1 + compute_sum_sse_16 v13, 1 + compute_sum_sse_16 v14, 1 + compute_sum_sse_16 v15, 0 + + variance_final v18, v19, v23, 8 + + addi r1, r1, 32 ;# recover stack + + mtspr 256, r11 ;# reset old VRSAVE + + blr + + .data + + .align 4 +hfilter_b: + .byte 128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0 + .byte 112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0,112, 16, 0, 0 + .byte 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0, 96, 32, 0, 0 + .byte 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0, 80, 48, 0, 0 + .byte 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0, 64, 64, 0, 0 + .byte 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0, 48, 80, 0, 0 + .byte 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0, 32, 96, 0, 0 + .byte 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0, 16,112, 0, 0 + + .align 4 +vfilter_b: + .byte 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + .byte 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + .byte 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 + .byte 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 + .byte 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112 + + .align 4 +b_hperm_b: + .byte 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 + + .align 4 +b_0123_b: + .byte 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 + + .align 4 +b_4567_b: + .byte 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10 + +b_hilo_b: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23
diff --git a/vp8/encoder/preproc.c b/vp8/encoder/preproc.c new file mode 100644 index 0000000..d2a13dc --- /dev/null +++ b/vp8/encoder/preproc.c
@@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/**************************************************************************** +* +* Module Title : preproc.c +* +* Description : Simple pre-processor. +* +****************************************************************************/ + +/**************************************************************************** +* Header Files +****************************************************************************/ + +#include "memory.h" +#include "preproc7.h" +#include "vpx_mem/vpx_mem.h" + +/**************************************************************************** +* Macros +****************************************************************************/ +#define FRAMECOUNT 7 +#define ROUNDUP32(X) ( ( ( (unsigned long) X ) + 31 )&( 0xFFFFFFE0 ) ) + +/**************************************************************************** +* Imports +****************************************************************************/ +extern void vp8_get_processor_flags(int *mmx_enabled, int *xmm_enabled, int *wmt_enabled); + +/**************************************************************************** +* Exported Global Variables +****************************************************************************/ +void (*temp_filter)(pre_proc_instance *ppi, unsigned char *s, unsigned char *d, int bytes, int strength); +void temp_filter_mmx +( + pre_proc_instance *ppi, + unsigned char *s, + unsigned char *d, + int bytes, + int strength +); +void temp_filter_wmt +( + pre_proc_instance *ppi, + unsigned char *s, + unsigned char *d, + int bytes, + int strength +); + +/**************************************************************************** + * + * ROUTINE : temp_filter_c + * + * INPUTS : pre_proc_instance *ppi : Pointer to pre-processor instance. + * unsigned char *s : Pointer to source frame. + * unsigned char *d : Pointer to destination frame. + * int bytes : Number of bytes to filter. + * int strength : Strength of filter to apply. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs a closesness adjusted temporarl blur + * + * SPECIAL NOTES : Destination frame can be same as source frame. + * + ****************************************************************************/ +void temp_filter_c +( + pre_proc_instance *ppi, + unsigned char *s, + unsigned char *d, + int bytes, + int strength +) +{ + int byte = 0; + unsigned char *frameptr = ppi->frame_buffer; + + if (ppi->frame == 0) + { + do + { + int frame = 0; + + do + { + *frameptr = s[byte]; + ++frameptr; + ++frame; + } + while (frame < FRAMECOUNT); + + d[byte] = s[byte]; + + ++byte; + } + while (byte < bytes); + } + else + { + int modifier; + int offset = (ppi->frame % FRAMECOUNT); + + do + { + int accumulator = 0; + int count = 0; + int frame = 0; + + frameptr[offset] = s[byte]; + + do + { + int pixel_value = *frameptr; + + modifier = s[byte]; + modifier -= pixel_value; + modifier *= modifier; + modifier >>= strength; + modifier *= 3; + + if (modifier > 16) + modifier = 16; + + modifier = 16 - modifier; + + accumulator += modifier * pixel_value; + + count += modifier; + + frameptr++; + + ++frame; + } + while (frame < FRAMECOUNT); + + accumulator += (count >> 1); + accumulator *= ppi->fixed_divide[count]; + accumulator >>= 16; + + d[byte] = accumulator; + + ++byte; + } + while (byte < bytes); + } + + ++ppi->frame; +} +/**************************************************************************** + * + * ROUTINE : delete_pre_proc + * + * INPUTS : pre_proc_instance *ppi : Pointer to pre-processor instance. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Deletes a pre-processing instance. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +void delete_pre_proc(pre_proc_instance *ppi) +{ + if (ppi->frame_buffer_alloc) + vpx_free(ppi->frame_buffer_alloc); + + ppi->frame_buffer_alloc = 0; + ppi->frame_buffer = 0; + + if (ppi->fixed_divide_alloc) + vpx_free(ppi->fixed_divide_alloc); + + ppi->fixed_divide_alloc = 0; + ppi->fixed_divide = 0; +} + +/**************************************************************************** + * + * ROUTINE : init_pre_proc + * + * INPUTS : pre_proc_instance *ppi : Pointer to pre-processor instance. + * int frame_size : Number of bytes in one frame. + * + * OUTPUTS : None. + * + * RETURNS : int: 1 if successful, 0 if failed. + * + * FUNCTION : Initializes prepprocessor instance. + * + * SPECIAL NOTES : None. + * + ****************************************************************************/ +int init_pre_proc7(pre_proc_instance *ppi, int frame_size) +{ + int i; + int mmx_enabled; + int xmm_enabled; + int wmt_enabled; + + vp8_get_processor_flags(&mmx_enabled, &xmm_enabled, &wmt_enabled); + + if (wmt_enabled) + temp_filter = temp_filter_wmt; + else if (mmx_enabled) + temp_filter = temp_filter_mmx; + else + temp_filter = temp_filter_c; + + + delete_pre_proc(ppi); + + ppi->frame_buffer_alloc = vpx_malloc(32 + frame_size * FRAMECOUNT * sizeof(unsigned char)); + + if (!ppi->frame_buffer_alloc) + { + delete_pre_proc(ppi); + return 0; + } + + ppi->frame_buffer = (unsigned char *) ROUNDUP32(ppi->frame_buffer_alloc); + + ppi->fixed_divide_alloc = vpx_malloc(32 + 255 * sizeof(unsigned int)); + + if (!ppi->fixed_divide_alloc) + { + delete_pre_proc(ppi); + return 0; + } + + ppi->fixed_divide = (unsigned int *) ROUNDUP32(ppi->fixed_divide_alloc); + + for (i = 1; i < 255; i++) + ppi->fixed_divide[i] = 0x10000 / i; + + return 1; +}
diff --git a/vp8/encoder/psnr.c b/vp8/encoder/psnr.c new file mode 100644 index 0000000..0e34cec --- /dev/null +++ b/vp8/encoder/psnr.c
@@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "math.h" +#include "systemdependent.h" /* for vp8_clear_system_state() */ + +#define MAX_PSNR 60 + +double vp8_mse2psnr(double Samples, double Peak, double Mse) +{ + double psnr; + + if ((double)Mse > 0.0) + psnr = 10.0 * log10(Peak * Peak * Samples / Mse); + else + psnr = MAX_PSNR; // Limit to prevent / 0 + + if (psnr > MAX_PSNR) + psnr = MAX_PSNR; + + return psnr; +} + +double vp8_calc_psnr(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, double *YPsnr, double *UPsnr, double *VPsnr, double *sq_error) +{ + int i, j; + int Diff; + double frame_psnr; + double Total; + double grand_total; + unsigned char *src = source->y_buffer; + unsigned char *dst = dest->y_buffer; + + Total = 0.0; + grand_total = 0.0; + + // Loop throught the Y plane raw and reconstruction data summing (square differences) + for (i = 0; i < source->y_height; i++) + { + + for (j = 0; j < source->y_width; j++) + { + Diff = (int)(src[j]) - (int)(dst[j]); + Total += Diff * Diff; + } + + src += source->y_stride; + dst += dest->y_stride; + } + + // Work out Y PSNR + *YPsnr = vp8_mse2psnr(source->y_height * source->y_width, 255.0, Total); + grand_total += Total; + Total = 0; + + + // Loop through the U plane + src = source->u_buffer; + dst = dest->u_buffer; + + for (i = 0; i < source->uv_height; i++) + { + + for (j = 0; j < source->uv_width; j++) + { + Diff = (int)(src[j]) - (int)(dst[j]); + Total += Diff * Diff; + } + + src += source->uv_stride; + dst += dest->uv_stride; + } + + // Work out U PSNR + *UPsnr = vp8_mse2psnr(source->uv_height * source->uv_width, 255.0, Total); + grand_total += Total; + Total = 0; + + + // V PSNR + src = source->v_buffer; + dst = dest->v_buffer; + + for (i = 0; i < source->uv_height; i++) + { + + for (j = 0; j < source->uv_width; j++) + { + Diff = (int)(src[j]) - (int)(dst[j]); + Total += Diff * Diff; + } + + src += source->uv_stride; + dst += dest->uv_stride; + } + + // Work out UV PSNR + *VPsnr = vp8_mse2psnr(source->uv_height * source->uv_width, 255.0, Total); + grand_total += Total; + Total = 0; + + // Work out total PSNR + frame_psnr = vp8_mse2psnr(source->y_height * source->y_width * 3 / 2 , 255.0, grand_total); + + *sq_error = 1.0 * grand_total; + + return frame_psnr; +}
diff --git a/vp8/encoder/psnr.h b/vp8/encoder/psnr.h new file mode 100644 index 0000000..9f6ca0b --- /dev/null +++ b/vp8/encoder/psnr.h
@@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_PSNR_H +#define __INC_PSNR_H + +extern double vp8_mse2psnr(double Samples, double Peak, double Mse); +extern double vp8_calc_psnr(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest, double *YPsnr, double *UPsnr, double *VPsnr, double *sq_error); + +#endif
diff --git a/vp8/encoder/quantize.c b/vp8/encoder/quantize.c new file mode 100644 index 0000000..6028ebf --- /dev/null +++ b/vp8/encoder/quantize.c
@@ -0,0 +1,249 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> +#include "vpx_mem/vpx_mem.h" + +#include "quantize.h" +#include "entropy.h" +#include "predictdc.h" + +void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *coeff_ptr = &b->coeff[0]; + short *zbin_ptr = &b->zbin[0][0]; + short *round_ptr = &b->round[0][0]; + short *quant_ptr = &b->quant[0][0]; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = &d->dequant[0][0]; + + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + zbin = zbin_ptr[rc] ; + + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + y = ((x + round_ptr[rc]) * quant_ptr[rc]) >> 16; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + } + } + } + + d->eob = eob + 1; + +} + +void vp8_regular_quantize_b(BLOCK *b, BLOCKD *d) +{ + int i, rc, eob; + int zbin; + int x, y, z, sz; + short *zbin_boost_ptr = &b->zrun_zbin_boost[0]; + short *coeff_ptr = &b->coeff[0]; + short *zbin_ptr = &b->zbin[0][0]; + short *round_ptr = &b->round[0][0]; + short *quant_ptr = &b->quant[0][0]; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = &d->dequant[0][0]; + short zbin_oq_value = b->zbin_extra; + + vpx_memset(qcoeff_ptr, 0, 32); + vpx_memset(dqcoeff_ptr, 0, 32); + + eob = -1; + + for (i = 0; i < 16; i++) + { + rc = vp8_default_zig_zag1d[i]; + z = coeff_ptr[rc]; + + //if ( i == 0 ) + // zbin = zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value/2; + //else + zbin = zbin_ptr[rc] + *zbin_boost_ptr + zbin_oq_value; + + zbin_boost_ptr ++; + sz = (z >> 31); // sign of z + x = (z ^ sz) - sz; // x = abs(z) + + if (x >= zbin) + { + y = ((x + round_ptr[rc]) * quant_ptr[rc]) >> 16; // quantize (x) + x = (y ^ sz) - sz; // get the sign back + qcoeff_ptr[rc] = x; // write to destination + dqcoeff_ptr[rc] = x * dequant_ptr[rc]; // dequantized value + + if (y) + { + eob = i; // last nonzero coeffs + zbin_boost_ptr = &b->zrun_zbin_boost[0]; // reset zero runlength + } + } + } + + d->eob = eob + 1; +} +void vp8_quantize_mby(MACROBLOCK *x) +{ + int i; + + if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV) + { + for (i = 0; i < 16; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2); + } + + x->quantize_b(&x->block[24], &x->e_mbd.block[24]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[24].eob); + + } + else + { + for (i = 0; i < 16; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } +} + +void vp8_quantize_mb(MACROBLOCK *x) +{ + int i; + + x->e_mbd.mbmi.mb_skip_coeff = 1; + + if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV) + { + for (i = 0; i < 16; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2); + } + + for (i = 16; i < 25; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } + else + { + for (i = 0; i < 24; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } + +} + + +void vp8_quantize_mbuv(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i++) + { + x->quantize_b(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } +} + +// This function is not currently called +void vp8_quantize_mbrd(MACROBLOCK *x) +{ + int i; + + x->e_mbd.mbmi.mb_skip_coeff = 1; + + if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV) + { + for (i = 0; i < 16; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2); + } + + for (i = 16; i < 25; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } + else + { + for (i = 0; i < 24; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } +} + +void vp8_quantize_mbuvrd(MACROBLOCK *x) +{ + int i; + + for (i = 16; i < 24; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } +} + +void vp8_quantize_mbyrd(MACROBLOCK *x) +{ + int i; + + if (x->e_mbd.mbmi.mode != B_PRED && x->e_mbd.mbmi.mode != SPLITMV) + { + for (i = 0; i < 16; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (x->e_mbd.block[i].eob < 2); + } + + x->quantize_brd(&x->block[24], &x->e_mbd.block[24]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[24].eob); + + } + else + { + for (i = 0; i < 16; i++) + { + x->quantize_brd(&x->block[i], &x->e_mbd.block[i]); + x->e_mbd.mbmi.mb_skip_coeff &= (!x->e_mbd.block[i].eob); + } + } +}
diff --git a/vp8/encoder/quantize.h b/vp8/encoder/quantize.h new file mode 100644 index 0000000..868e8e3 --- /dev/null +++ b/vp8/encoder/quantize.h
@@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_QUANTIZE_H +#define __INC_QUANTIZE_H + +#include "block.h" + +#define prototype_quantize_block(sym) \ + void (sym)(BLOCK *b,BLOCKD *d) + +#if ARCH_ARM +#include "arm/quantize_arm.h" +#endif + +#ifndef vp8_quantize_quantb +#define vp8_quantize_quantb vp8_regular_quantize_b +#endif +extern prototype_quantize_block(vp8_quantize_quantb); + +#ifndef vp8_quantize_fastquantb +#define vp8_quantize_fastquantb vp8_fast_quantize_b_c +#endif +extern prototype_quantize_block(vp8_quantize_fastquantb); + +typedef struct +{ + prototype_quantize_block(*quantb); + prototype_quantize_block(*fastquantb); +} vp8_quantize_rtcd_vtable_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define QUANTIZE_INVOKE(ctx,fn) (ctx)->fn +#else +#define QUANTIZE_INVOKE(ctx,fn) vp8_quantize_##fn +#endif + +extern void vp8_quantize_mb(MACROBLOCK *x); +extern void vp8_quantize_mbuv(MACROBLOCK *x); +extern void vp8_quantize_mby(MACROBLOCK *x); +extern void vp8_quantize_mbyrd(MACROBLOCK *x); +extern void vp8_quantize_mbuvrd(MACROBLOCK *x); +extern void vp8_quantize_mbrd(MACROBLOCK *x); + +#endif
diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c new file mode 100644 index 0000000..05040d3 --- /dev/null +++ b/vp8/encoder/ratectrl.c
@@ -0,0 +1,1552 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <assert.h> + +#include "math.h" +#include "common.h" +#include "ratectrl.h" +#include "entropymode.h" +#include "vpx_mem/vpx_mem.h" +#include "systemdependent.h" +#include "encodemv.h" + + +#define MIN_BPB_FACTOR 0.01 +#define MAX_BPB_FACTOR 50 + +extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; +extern const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES]; + + + +#ifdef MODE_STATS +extern int y_modes[5]; +extern int uv_modes[4]; +extern int b_modes[10]; + +extern int inter_y_modes[10]; +extern int inter_uv_modes[4]; +extern int inter_b_modes[10]; +#endif + +// Bits Per MB at different Q (Multiplied by 512) +#define BPER_MB_NORMBITS 9 + +const int vp8_bits_per_mb[2][QINDEX_RANGE] = +{ + // (Updated 19 March 08) Baseline estimate of INTRA-frame Bits Per MB at each Q: + { + 674781, 606845, 553905, 524293, 500428, 452540, 435379, 414719, + 390970, 371082, 359416, 341807, 336957, 317263, 303724, 298402, + 285688, 275237, 268455, 262560, 256038, 248734, 241087, 237615, + 229247, 225211, 219112, 213920, 211559, 202714, 198482, 193401, + 187866, 183453, 179212, 175965, 171852, 167235, 163972, 160560, + 156032, 154349, 151390, 148725, 145708, 142311, 139981, 137700, + 134084, 131863, 129746, 128498, 126077, 123461, 121290, 117782, + 114883, 112332, 108410, 105685, 103434, 101192, 98587, 95959, + 94059, 92017, 89970, 87936, 86142, 84801, 82736, 81106, + 79668, 78135, 76641, 75103, 73943, 72693, 71401, 70098, + 69165, 67901, 67170, 65987, 64923, 63534, 62378, 61302, + 59921, 58941, 57844, 56782, 55960, 54973, 54257, 53454, + 52230, 50938, 49962, 49190, 48288, 47270, 46738, 46037, + 45020, 44027, 43216, 42287, 41594, 40702, 40081, 39414, + 38282, 37627, 36987, 36375, 35808, 35236, 34710, 34162, + 33659, 33327, 32751, 32384, 31936, 31461, 30982, 30582, + }, + + // (Updated 19 March 08) Baseline estimate of INTER-frame Bits Per MB at each Q: + { + 497401, 426316, 372064, 352732, 335763, 283921, 273848, 253321, + 233181, 217727, 210030, 196685, 194836, 178396, 167753, 164116, + 154119, 146929, 142254, 138488, 133591, 127741, 123166, 120226, + 114188, 111756, 107882, 104749, 102522, 96451, 94424, 90905, + 87286, 84931, 82111, 80534, 77610, 74700, 73037, 70715, + 68006, 67235, 65374, 64009, 62134, 60180, 59105, 57691, + 55509, 54512, 53318, 52693, 51194, 49840, 48944, 46980, + 45668, 44177, 42348, 40994, 39859, 38889, 37717, 36391, + 35482, 34622, 33795, 32756, 32002, 31492, 30573, 29737, + 29152, 28514, 27941, 27356, 26859, 26329, 25874, 25364, + 24957, 24510, 24290, 23689, 23380, 22845, 22481, 22066, + 21587, 21219, 20880, 20452, 20260, 19926, 19661, 19334, + 18915, 18391, 18046, 17833, 17441, 17105, 16888, 16729, + 16383, 16023, 15706, 15442, 15222, 14938, 14673, 14452, + 14005, 13807, 13611, 13447, 13223, 13102, 12963, 12801, + 12627, 12534, 12356, 12228, 12056, 11907, 11746, 11643, + } +}; + +const int vp8_kf_boost_qadjustment[QINDEX_RANGE] = +{ + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 200, 201, 201, 202, 203, 203, 203, + 204, 204, 205, 205, 206, 206, 207, 207, + 208, 208, 209, 209, 210, 210, 211, 211, + 212, 212, 213, 213, 214, 214, 215, 215, + 216, 216, 217, 217, 218, 218, 219, 219, + 220, 220, 220, 220, 220, 220, 220, 220, + 220, 220, 220, 220, 220, 220, 220, 220, +}; + +//#define GFQ_ADJUSTMENT (Q+100) +#define GFQ_ADJUSTMENT vp8_gf_boost_qadjustment[Q] +const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = +{ + 80, 82, 84, 86, 88, 90, 92, 94, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 184, 185, 185, 186, 186, 187, 187, + 188, 188, 189, 189, 190, 190, 191, 191, + 192, 192, 193, 193, 194, 194, 194, 194, + 195, 195, 196, 196, 197, 197, 198, 198 +}; + +/* +const int vp8_gf_boost_qadjustment[QINDEX_RANGE] = +{ + 100,101,102,103,104,105,105,106, + 106,107,107,108,109,109,110,111, + 112,113,114,115,116,117,118,119, + 120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151, + 152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167, + 168,169,170,170,171,171,172,172, + 173,173,173,174,174,174,175,175, + 175,176,176,176,177,177,177,177, + 178,178,179,179,180,180,181,181, + 182,182,183,183,184,184,185,185, + 186,186,187,187,188,188,189,189, + 190,190,191,191,192,192,193,193, +}; +*/ + +const int vp8_kf_gf_boost_qlimits[QINDEX_RANGE] = +{ + 150, 155, 160, 165, 170, 175, 180, 185, + 190, 195, 200, 205, 210, 215, 220, 225, + 230, 235, 240, 245, 250, 255, 260, 265, + 270, 275, 280, 285, 290, 295, 300, 305, + 310, 320, 330, 340, 350, 360, 370, 380, + 390, 400, 410, 420, 430, 440, 450, 460, + 470, 480, 490, 500, 510, 520, 530, 540, + 550, 560, 570, 580, 590, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, +}; + +// % adjustment to target kf size based on seperation from previous frame +const int vp8_kf_boost_seperationt_adjustment[16] = +{ + 30, 40, 50, 55, 60, 65, 70, 75, + 80, 85, 90, 95, 100, 100, 100, 100, +}; + + +const int vp8_gf_adjust_table[101] = +{ + 100, + 115, 130, 145, 160, 175, 190, 200, 210, 220, 230, + 240, 260, 270, 280, 290, 300, 310, 320, 330, 340, + 350, 360, 370, 380, 390, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 400, 400, 400, +}; + +const int vp8_gf_intra_useage_adjustment[20] = +{ + 125, 120, 115, 110, 105, 100, 95, 85, 80, 75, + 70, 65, 60, 55, 50, 50, 50, 50, 50, 50, +}; + +const int vp8_gf_interval_table[101] = +{ + 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +}; + +static const unsigned int prior_key_frame_weight[KEY_FRAME_CONTEXT] = { 1, 2, 3, 4, 5 }; + + +void vp8_save_coding_context(VP8_COMP *cpi) +{ + CODING_CONTEXT *const cc = & cpi->coding_context; + + // Stores a snapshot of key state variables which can subsequently be + // restored with a call to vp8_restore_coding_context. These functions are + // intended for use in a re-code loop in vp8_compress_frame where the + // quantizer value is adjusted between loop iterations. + + cc->frames_since_key = cpi->frames_since_key; + cc->filter_level = cpi->common.filter_level; + cc->frames_till_gf_update_due = cpi->frames_till_gf_update_due; + cc->frames_since_golden = cpi->common.frames_since_golden; + + vp8_copy(cc->mvc, cpi->common.fc.mvc); + vp8_copy(cc->mvcosts, cpi->mb.mvcosts); + + vp8_copy(cc->kf_ymode_prob, cpi->common.kf_ymode_prob); + vp8_copy(cc->ymode_prob, cpi->common.fc.ymode_prob); + vp8_copy(cc->kf_uv_mode_prob, cpi->common.kf_uv_mode_prob); + vp8_copy(cc->uv_mode_prob, cpi->common.fc.uv_mode_prob); + + vp8_copy(cc->ymode_count, cpi->ymode_count); + vp8_copy(cc->uv_mode_count, cpi->uv_mode_count); + + + // Stats +#ifdef MODE_STATS + vp8_copy(cc->y_modes, y_modes); + vp8_copy(cc->uv_modes, uv_modes); + vp8_copy(cc->b_modes, b_modes); + vp8_copy(cc->inter_y_modes, inter_y_modes); + vp8_copy(cc->inter_uv_modes, inter_uv_modes); + vp8_copy(cc->inter_b_modes, inter_b_modes); +#endif + + cc->this_frame_percent_intra = cpi->this_frame_percent_intra; +} + + +void vp8_restore_coding_context(VP8_COMP *cpi) +{ + CODING_CONTEXT *const cc = & cpi->coding_context; + + // Restore key state variables to the snapshot state stored in the + // previous call to vp8_save_coding_context. + + cpi->frames_since_key = cc->frames_since_key; + cpi->common.filter_level = cc->filter_level; + cpi->frames_till_gf_update_due = cc->frames_till_gf_update_due; + cpi->common.frames_since_golden = cc->frames_since_golden; + + vp8_copy(cpi->common.fc.mvc, cc->mvc); + + vp8_copy(cpi->mb.mvcosts, cc->mvcosts); + + vp8_copy(cpi->common.kf_ymode_prob, cc->kf_ymode_prob); + vp8_copy(cpi->common.fc.ymode_prob, cc->ymode_prob); + vp8_copy(cpi->common.kf_uv_mode_prob, cc->kf_uv_mode_prob); + vp8_copy(cpi->common.fc.uv_mode_prob, cc->uv_mode_prob); + + vp8_copy(cpi->ymode_count, cc->ymode_count); + vp8_copy(cpi->uv_mode_count, cc->uv_mode_count); + + // Stats +#ifdef MODE_STATS + vp8_copy(y_modes, cc->y_modes); + vp8_copy(uv_modes, cc->uv_modes); + vp8_copy(b_modes, cc->b_modes); + vp8_copy(inter_y_modes, cc->inter_y_modes); + vp8_copy(inter_uv_modes, cc->inter_uv_modes); + vp8_copy(inter_b_modes, cc->inter_b_modes); +#endif + + + cpi->this_frame_percent_intra = cc->this_frame_percent_intra; +} + + +void vp8_setup_key_frame(VP8_COMP *cpi) +{ + // Setup for Key frame: + + vp8_default_coef_probs(& cpi->common); + vp8_kf_default_bmode_probs(cpi->common.kf_bmode_prob); + + vpx_memcpy(cpi->common.fc.mvc, vp8_default_mv_context, sizeof(vp8_default_mv_context)); + { + int flag[2] = {1, 1}; + vp8_build_component_cost_table(cpi->mb.mvcost, cpi->mb.mvsadcost, (const MV_CONTEXT *) cpi->common.fc.mvc, flag); + } + + vpx_memset(cpi->common.fc.pre_mvc, 0, sizeof(cpi->common.fc.pre_mvc)); //initialize pre_mvc to all zero. + + //cpi->common.filter_level = 0; // Reset every key frame. + cpi->common.filter_level = cpi->common.base_qindex * 3 / 8 ; + + // Provisional interval before next GF + if (cpi->auto_gold) + //cpi->frames_till_gf_update_due = DEFAULT_GF_INTERVAL; + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + else + cpi->frames_till_gf_update_due = cpi->goldfreq; + + cpi->common.refresh_golden_frame = TRUE; +} + +void vp8_calc_auto_iframe_target_size(VP8_COMP *cpi) +{ + // boost defaults to half second + int kf_boost; + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); //__asm emms; + + if (cpi->oxcf.fixed_q >= 0) + { + vp8_calc_iframe_target_size(cpi); + return; + } + + if (cpi->pass == 2) + { + cpi->this_frame_target = cpi->per_frame_bandwidth; // New Two pass RC + } + else + { + // Boost depends somewhat on frame rate + kf_boost = (int)(2 * cpi->output_frame_rate - 16); + + // adjustment up based on q + kf_boost = kf_boost * vp8_kf_boost_qadjustment[cpi->ni_av_qi] / 100; + + // frame separation adjustment ( down) + if (cpi->frames_since_key < cpi->output_frame_rate / 2) + kf_boost = (int)(kf_boost * cpi->frames_since_key / (cpi->output_frame_rate / 2)); + + if (kf_boost < 16) + kf_boost = 16; + + // Reset the active worst quality to the baseline value for key frames. + cpi->active_worst_quality = cpi->worst_quality; + + cpi->this_frame_target = ((16 + kf_boost) * cpi->per_frame_bandwidth) >> 4; + } + + + // Should the next frame be an altref frame + if (cpi->pass != 2) + { + // For now Alt ref is not allowed except in 2 pass modes. + cpi->source_alt_ref_pending = FALSE; + + /*if ( cpi->oxcf.fixed_q == -1) + { + if ( cpi->oxcf.play_alternate && ( (cpi->last_boost/2) > (100+(AF_THRESH*cpi->frames_till_gf_update_due)) ) ) + cpi->source_alt_ref_pending = TRUE; + else + cpi->source_alt_ref_pending = FALSE; + }*/ + } + + if (0) + { + FILE *f; + + f = fopen("kf_boost.stt", "a"); + //fprintf(f, " %8d %10d %10d %10d %10d %10d %10d\n", + // cpi->common.current_video_frame, cpi->target_bandwidth, cpi->frames_to_key, kf_boost_qadjustment[cpi->ni_av_qi], cpi->kf_boost, (cpi->this_frame_target *100 / cpi->per_frame_bandwidth), cpi->this_frame_target ); + + fprintf(f, " %8u %10d %10d %10d\n", + cpi->common.current_video_frame, cpi->gfu_boost, cpi->baseline_gf_interval, cpi->source_alt_ref_pending); + + fclose(f); + } +} + +// Do the best we can to define the parameteres for the next GF based on what information we have available. +static void calc_gf_params(VP8_COMP *cpi) +{ + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int Boost = 0; + + int gf_frame_useage = 0; // Golden frame useage since last GF + int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + + cpi->recent_ref_frame_usage[LAST_FRAME] + + cpi->recent_ref_frame_usage[GOLDEN_FRAME] + + cpi->recent_ref_frame_usage[ALTREF_FRAME]; + + int pct_gf_active = (100 * cpi->common.gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); + + // Reset the last boost indicator + //cpi->last_boost = 100; + + if (tot_mbs) + gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; + + if (pct_gf_active > gf_frame_useage) + gf_frame_useage = pct_gf_active; + + // Not two pass + if (cpi->pass != 2) + { + // Single Pass lagged mode: TBD + if (FALSE) + { + } + + // Single Pass compression: Has to use current and historical data + else + { +#if 0 + // Experimental code + int index = cpi->one_pass_frame_index; + int frames_to_scan = (cpi->max_gf_interval <= MAX_LAG_BUFFERS) ? cpi->max_gf_interval : MAX_LAG_BUFFERS; + + /* + // *************** Experimental code - incomplete + double decay_val = 1.0; + double IIAccumulator = 0.0; + double last_iiaccumulator = 0.0; + double IIRatio; + + cpi->one_pass_frame_index = cpi->common.current_video_frame%MAX_LAG_BUFFERS; + + for ( i = 0; i < (frames_to_scan - 1); i++ ) + { + if ( index < 0 ) + index = MAX_LAG_BUFFERS; + index --; + + if ( cpi->one_pass_frame_stats[index].frame_coded_error > 0.0 ) + { + IIRatio = cpi->one_pass_frame_stats[index].frame_intra_error / cpi->one_pass_frame_stats[index].frame_coded_error; + + if ( IIRatio > 30.0 ) + IIRatio = 30.0; + } + else + IIRatio = 30.0; + + IIAccumulator += IIRatio * decay_val; + + decay_val = decay_val * cpi->one_pass_frame_stats[index].frame_pcnt_inter; + + if ( (i > MIN_GF_INTERVAL) && + ((IIAccumulator - last_iiaccumulator) < 2.0) ) + { + break; + } + last_iiaccumulator = IIAccumulator; + } + + Boost = IIAccumulator*100.0/16.0; + cpi->baseline_gf_interval = i; + + */ +#else + + /*************************************************************/ + // OLD code + + // Adjust boost based upon ambient Q + Boost = GFQ_ADJUSTMENT; + + // Adjust based upon most recently measure intra useage + Boost = Boost * vp8_gf_intra_useage_adjustment[(cpi->this_frame_percent_intra < 15) ? cpi->this_frame_percent_intra : 14] / 100; + + // Adjust gf boost based upon GF usage since last GF + Boost = Boost * vp8_gf_adjust_table[gf_frame_useage] / 100; +#endif + } + + // golden frame boost without recode loop often goes awry. be safe by keeping numbers down. + if (!cpi->sf.recode_loop) + { + if (cpi->compressor_speed == 2) + Boost = Boost / 2; + } + + // Apply an upper limit based on Q for 1 pass encodes + if (Boost > vp8_kf_gf_boost_qlimits[Q] && (cpi->pass == 0)) + Boost = vp8_kf_gf_boost_qlimits[Q]; + + // Apply lower limits to boost. + else if (Boost < 110) + Boost = 110; + + // Note the boost used + cpi->last_boost = Boost; + + } + + // Estimate next interval + // This is updated once the real frame size/boost is known. + if (cpi->oxcf.fixed_q == -1) + { + if (cpi->pass == 2) // 2 Pass + { + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + } + else // 1 Pass + { + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + + if (cpi->last_boost > 750) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost > 1000) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost > 1250) + cpi->frames_till_gf_update_due++; + + if (cpi->last_boost >= 1500) + cpi->frames_till_gf_update_due ++; + + if (vp8_gf_interval_table[gf_frame_useage] > cpi->frames_till_gf_update_due) + cpi->frames_till_gf_update_due = vp8_gf_interval_table[gf_frame_useage]; + + if (cpi->frames_till_gf_update_due > cpi->max_gf_interval) + cpi->frames_till_gf_update_due = cpi->max_gf_interval; + } + } + else + cpi->frames_till_gf_update_due = cpi->baseline_gf_interval; + + // ARF on or off + if (cpi->pass != 2) + { + // For now Alt ref is not allowed except in 2 pass modes. + cpi->source_alt_ref_pending = FALSE; + + /*if ( cpi->oxcf.fixed_q == -1) + { + if ( cpi->oxcf.play_alternate && (cpi->last_boost > (100 + (AF_THRESH*cpi->frames_till_gf_update_due)) ) ) + cpi->source_alt_ref_pending = TRUE; + else + cpi->source_alt_ref_pending = FALSE; + }*/ + } +} +/* This is equvialent to estimate_bits_at_q without the rate_correction_factor. */ +static int baseline_bits_at_q(int frame_kind, int Q, int MBs) +{ + int Bpm = vp8_bits_per_mb[frame_kind][Q]; + + /* Attempt to retain reasonable accuracy without overflow. The cutoff is + * chosen such that the maximum product of Bpm and MBs fits 31 bits. The + * largest Bpm takes 20 bits. + */ + if (MBs > (1 << 11)) + return (Bpm >> BPER_MB_NORMBITS) * MBs; + else + return (Bpm * MBs) >> BPER_MB_NORMBITS; +} + +void vp8_calc_iframe_target_size(VP8_COMP *cpi) +{ + int Q; + int Boost = 100; + + Q = (cpi->oxcf.fixed_q >= 0) ? cpi->oxcf.fixed_q : cpi->avg_frame_qindex; + + if (cpi->auto_adjust_key_quantizer == 1) + { + // If (auto_adjust_key_quantizer==1) then a lower Q is selected for key-frames. + // The enhanced Q is calculated so as to boost the key frame size by a factor + // specified in kf_boost_qadjustment. Also, can adjust based on distance + // between key frames. + + // Adjust boost based upon ambient Q + Boost = vp8_kf_boost_qadjustment[Q]; + + // Make the Key frame boost less if the seperation from the previous key frame is small + if (cpi->frames_since_key < 16) + Boost = Boost * vp8_kf_boost_seperationt_adjustment[cpi->frames_since_key] / 100; + else + Boost = Boost * vp8_kf_boost_seperationt_adjustment[15] / 100; + + // Apply limits on boost + if (Boost > vp8_kf_gf_boost_qlimits[Q]) + Boost = vp8_kf_gf_boost_qlimits[Q]; + else if (Boost < 120) + Boost = 120; + } + + // Keep a record of the boost that was used + cpi->last_boost = Boost; + + // Should the next frame be an altref frame + if (cpi->pass != 2) + { + // For now Alt ref is not allowed except in 2 pass modes. + cpi->source_alt_ref_pending = FALSE; + + /*if ( cpi->oxcf.fixed_q == -1) + { + if ( cpi->oxcf.play_alternate && ( (cpi->last_boost/2) > (100+(AF_THRESH*cpi->frames_till_gf_update_due)) ) ) + cpi->source_alt_ref_pending = TRUE; + else + cpi->source_alt_ref_pending = FALSE; + }*/ + } + + if (cpi->oxcf.fixed_q >= 0) + { + cpi->this_frame_target = (baseline_bits_at_q(0, Q, cpi->common.MBs) * Boost) / 100; + } + else + { + + int bits_per_mb_at_this_q ; + + if (cpi->oxcf.error_resilient_mode == 1) + { + cpi->this_frame_target = 2 * cpi->av_per_frame_bandwidth; + return; + } + + // Rate targetted scenario: + // Be careful of 32-bit OVERFLOW if restructuring the caluclation of cpi->this_frame_target + bits_per_mb_at_this_q = (int)(.5 + + cpi->key_frame_rate_correction_factor * vp8_bits_per_mb[0][Q]); + + cpi->this_frame_target = (((bits_per_mb_at_this_q * cpi->common.MBs) >> BPER_MB_NORMBITS) * Boost) / 100; + + // Reset the active worst quality to the baseline value for key frames. + if (cpi->pass < 2) + cpi->active_worst_quality = cpi->worst_quality; + } +} + + + +void vp8_calc_pframe_target_size(VP8_COMP *cpi) +{ + int min_frame_target; + int Adjustment; + + // Set the min frame bandwidth. + //min_frame_target = estimate_min_frame_size( cpi ); + min_frame_target = 0; + + if (cpi->pass == 2) + { + min_frame_target = cpi->min_frame_bandwidth; + + if (min_frame_target < (cpi->av_per_frame_bandwidth >> 5)) + min_frame_target = cpi->av_per_frame_bandwidth >> 5; + } + else if (min_frame_target < cpi->per_frame_bandwidth / 4) + min_frame_target = cpi->per_frame_bandwidth / 4; + + + // Special alt reference frame case + if (cpi->common.refresh_alt_ref_frame) + { + if (cpi->pass == 2) + { + cpi->per_frame_bandwidth = cpi->gf_bits; // Per frame bit target for the alt ref frame + cpi->this_frame_target = cpi->per_frame_bandwidth; + } + + /* One Pass ??? TBD */ + /*else + { + int frames_in_section; + int allocation_chunks; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + int alt_boost; + int max_arf_rate; + + alt_boost = (cpi->gfu_boost * 3 * GFQ_ADJUSTMENT) / (2 * 100); + alt_boost += (cpi->frames_till_gf_update_due * 50); + + // If alt ref is not currently active then we have a pottential double hit with GF and ARF so reduce the boost a bit. + // A similar thing is done on GFs that preceed a arf update. + if ( !cpi->source_alt_ref_active ) + alt_boost = alt_boost * 3 / 4; + + frames_in_section = cpi->frames_till_gf_update_due+1; // Standard frames + GF + allocation_chunks = (frames_in_section * 100) + alt_boost; + + // Normalize Altboost and allocations chunck down to prevent overflow + while ( alt_boost > 1000 ) + { + alt_boost /= 2; + allocation_chunks /= 2; + } + + else + { + int bits_in_section; + + if ( cpi->kf_overspend_bits > 0 ) + { + Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; + + if ( Adjustment > (cpi->per_frame_bandwidth - min_frame_target) ) + Adjustment = (cpi->per_frame_bandwidth - min_frame_target); + + cpi->kf_overspend_bits -= Adjustment; + + // Calculate an inter frame bandwidth target for the next few frames designed to recover + // any extra bits spent on the key frame. + cpi->inter_frame_target = cpi->per_frame_bandwidth - Adjustment; + if ( cpi->inter_frame_target < min_frame_target ) + cpi->inter_frame_target = min_frame_target; + } + else + cpi->inter_frame_target = cpi->per_frame_bandwidth; + + bits_in_section = cpi->inter_frame_target * frames_in_section; + + // Avoid loss of precision but avoid overflow + if ( (bits_in_section>>7) > allocation_chunks ) + cpi->this_frame_target = alt_boost * (bits_in_section / allocation_chunks); + else + cpi->this_frame_target = (alt_boost * bits_in_section) / allocation_chunks; + } + } + */ + } + + // Normal frames (gf,and inter) + else + { + // 2 pass + if (cpi->pass == 2) + { + cpi->this_frame_target = cpi->per_frame_bandwidth; + } + // 1 pass + else + { + // Make rate adjustment to recover bits spent in key frame + // Test to see if the key frame inter data rate correction should still be in force + if (cpi->kf_overspend_bits > 0) + { + Adjustment = (cpi->kf_bitrate_adjustment <= cpi->kf_overspend_bits) ? cpi->kf_bitrate_adjustment : cpi->kf_overspend_bits; + + if (Adjustment > (cpi->per_frame_bandwidth - min_frame_target)) + Adjustment = (cpi->per_frame_bandwidth - min_frame_target); + + cpi->kf_overspend_bits -= Adjustment; + + // Calculate an inter frame bandwidth target for the next few frames designed to recover + // any extra bits spent on the key frame. + cpi->this_frame_target = cpi->per_frame_bandwidth - Adjustment; + + if (cpi->this_frame_target < min_frame_target) + cpi->this_frame_target = min_frame_target; + } + else + cpi->this_frame_target = cpi->per_frame_bandwidth; + + // If appropriate make an adjustment to recover bits spent on a recent GF + if ((cpi->gf_overspend_bits > 0) && (cpi->this_frame_target > min_frame_target)) + { + int Adjustment = (cpi->non_gf_bitrate_adjustment <= cpi->gf_overspend_bits) ? cpi->non_gf_bitrate_adjustment : cpi->gf_overspend_bits; + + if (Adjustment > (cpi->this_frame_target - min_frame_target)) + Adjustment = (cpi->this_frame_target - min_frame_target); + + cpi->gf_overspend_bits -= Adjustment; + cpi->this_frame_target -= Adjustment; + } + + // Apply small + and - boosts for non gf frames + if ((cpi->last_boost > 150) && (cpi->frames_till_gf_update_due > 0) && + (cpi->current_gf_interval >= (MIN_GF_INTERVAL << 1))) + { + // % Adjustment limited to the range 1% to 10% + Adjustment = (cpi->last_boost - 100) >> 5; + + if (Adjustment < 1) + Adjustment = 1; + else if (Adjustment > 10) + Adjustment = 10; + + // Convert to bits + Adjustment = (cpi->this_frame_target * Adjustment) / 100; + + if (Adjustment > (cpi->this_frame_target - min_frame_target)) + Adjustment = (cpi->this_frame_target - min_frame_target); + + if (cpi->common.frames_since_golden == (cpi->current_gf_interval >> 1)) + cpi->this_frame_target += ((cpi->current_gf_interval - 1) * Adjustment); + else + cpi->this_frame_target -= Adjustment; + } + } + } + + // Set a reduced data rate target for our initial Q calculation. + // This should help to save bits during earier sections. + if ((cpi->oxcf.under_shoot_pct > 0) && (cpi->oxcf.under_shoot_pct <= 100)) + cpi->this_frame_target = (cpi->this_frame_target * cpi->oxcf.under_shoot_pct) / 100; + + // Sanity check that the total sum of adjustments is not above the maximum allowed + // That is that having allowed for KF and GF penalties we have not pushed the + // current interframe target to low. If the adjustment we apply here is not capable of recovering + // all the extra bits we have spent in the KF or GF then the remainder will have to be recovered over + // a longer time span via other buffer / rate control mechanisms. + if (cpi->this_frame_target < min_frame_target) + cpi->this_frame_target = min_frame_target; + + if (!cpi->common.refresh_alt_ref_frame) + // Note the baseline target data rate for this inter frame. + cpi->inter_frame_target = cpi->this_frame_target; + + // One Pass specific code + if (cpi->pass == 0) + { + // Adapt target frame size with respect to any buffering constraints: + if (cpi->buffered_mode) + { + int one_percent_bits = 1 + cpi->oxcf.optimal_buffer_level / 100; + + if ((cpi->buffer_level < cpi->oxcf.optimal_buffer_level) || (cpi->bits_off_target < cpi->oxcf.optimal_buffer_level)) + { + int percent_low = 0; + + // Decide whether or not we need to adjust the frame data rate target. + // + // If we are are below the optimal buffer fullness level and adherence + // to buffering contraints is important to the end useage then adjust + // the per frame target. + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && (cpi->buffer_level < cpi->oxcf.optimal_buffer_level)) + { + percent_low = (cpi->oxcf.optimal_buffer_level - cpi->buffer_level) / one_percent_bits; + + if (percent_low > 100) + percent_low = 100; + else if (percent_low < 0) + percent_low = 0; + } + // Are we overshooting the long term clip data rate... + else if (cpi->bits_off_target < 0) + { + // Adjust per frame data target downwards to compensate. + percent_low = (int)(100 * -cpi->bits_off_target / (cpi->total_byte_count * 8)); + + if (percent_low > 100) + percent_low = 100; + else if (percent_low < 0) + percent_low = 0; + } + + // lower the target bandwidth for this frame. + cpi->this_frame_target = (cpi->this_frame_target * (100 - (percent_low / 2))) / 100; + + // Are we using allowing control of active_worst_allowed_q according to buffer level. + if (cpi->auto_worst_q) + { + int critical_buffer_level; + + // For streaming applications the most important factor is cpi->buffer_level as this takes + // into account the specified short term buffering constraints. However, hitting the long + // term clip data rate target is also important. + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + // Take the smaller of cpi->buffer_level and cpi->bits_off_target + critical_buffer_level = (cpi->buffer_level < cpi->bits_off_target) ? cpi->buffer_level : cpi->bits_off_target; + } + // For local file playback short term buffering contraints are less of an issue + else + { + // Consider only how we are doing for the clip as a whole + critical_buffer_level = cpi->bits_off_target; + } + + // Set the active worst quality based upon the selected buffer fullness number. + if (critical_buffer_level < cpi->oxcf.optimal_buffer_level) + { + if (critical_buffer_level > (cpi->oxcf.optimal_buffer_level / 4)) + { + int qadjustment_range = cpi->worst_quality - cpi->ni_av_qi; + int above_base = (critical_buffer_level - (cpi->oxcf.optimal_buffer_level / 4)); + + // Step active worst quality down from cpi->ni_av_qi when (critical_buffer_level == cpi->optimal_buffer_level) + // to cpi->oxcf.worst_allowed_q when (critical_buffer_level == cpi->optimal_buffer_level/4) + cpi->active_worst_quality = cpi->worst_quality - ((qadjustment_range * above_base) / (cpi->oxcf.optimal_buffer_level * 3 / 4)); + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + else + { + cpi->active_worst_quality = cpi->ni_av_qi; + } + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + else + { + int percent_high; + + if (cpi->bits_off_target > cpi->oxcf.optimal_buffer_level) + { + percent_high = (int)(100 * (cpi->bits_off_target - cpi->oxcf.optimal_buffer_level) / (cpi->total_byte_count * 8)); + + if (percent_high > 100) + percent_high = 100; + else if (percent_high < 0) + percent_high = 0; + + cpi->this_frame_target = (cpi->this_frame_target * (100 + (percent_high / 2))) / 100; + + } + + // Are we allowing control of active_worst_allowed_q according to bufferl level. + if (cpi->auto_worst_q) + { + // When using the relaxed buffer model stick to the user specified value + cpi->active_worst_quality = cpi->ni_av_qi; + } + else + { + cpi->active_worst_quality = cpi->worst_quality; + } + } + + // Set active_best_quality to prevent quality rising too high + cpi->active_best_quality = cpi->best_quality; + + // Worst quality obviously must not be better than best quality + if (cpi->active_worst_quality <= cpi->active_best_quality) + cpi->active_worst_quality = cpi->active_best_quality + 1; + + } + // Unbuffered mode (eg. video conferencing) + else + { + // Set the active worst quality + cpi->active_worst_quality = cpi->worst_quality; + } + } + + // Test to see if we have to drop a frame + // The auto-drop frame code is only used in buffered mode. + // In unbufferd mode (eg vide conferencing) the descision to + // code or drop a frame is made outside the codec in response to real + // world comms or buffer considerations. + if (cpi->drop_frames_allowed && cpi->buffered_mode && + (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + ((cpi->common.frame_type != KEY_FRAME))) //|| !cpi->oxcf.allow_spatial_resampling) ) + { + // Check for a buffer underun-crisis in which case we have to drop a frame + if ((cpi->buffer_level < 0)) + { +#if 0 + FILE *f = fopen("dec.stt", "a"); + fprintf(f, "%10d %10d %10d %10d ***** BUFFER EMPTY\n", + (int) cpi->common.current_video_frame, + cpi->decimation_factor, cpi->common.horiz_scale, + (cpi->buffer_level * 100) / cpi->oxcf.optimal_buffer_level); + fclose(f); +#endif + //vpx_log("Decoder: Drop frame due to bandwidth: %d \n",cpi->buffer_level, cpi->av_per_frame_bandwidth); + + cpi->drop_frame = TRUE; + } + +#if 0 + // Check for other drop frame crtieria (Note 2 pass cbr uses decimation on whole KF sections) + else if ((cpi->buffer_level < cpi->oxcf.drop_frames_water_mark * cpi->oxcf.optimal_buffer_level / 100) && + (cpi->drop_count < cpi->max_drop_count) && (cpi->pass == 0)) + { + cpi->drop_frame = TRUE; + } + +#endif + + if (cpi->drop_frame) + { + // Update the buffer level variable. + cpi->bits_off_target += cpi->av_per_frame_bandwidth; + cpi->buffer_level = cpi->bits_off_target; + } + else + cpi->drop_count = 0; + } + + // Adjust target frame size for Golden Frames: + if (cpi->oxcf.error_resilient_mode == 0 && + (cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) + { + //int Boost = 0; + int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q; + + int gf_frame_useage = 0; // Golden frame useage since last GF + int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] + + cpi->recent_ref_frame_usage[LAST_FRAME] + + cpi->recent_ref_frame_usage[GOLDEN_FRAME] + + cpi->recent_ref_frame_usage[ALTREF_FRAME]; + + int pct_gf_active = (100 * cpi->common.gf_active_count) / (cpi->common.mb_rows * cpi->common.mb_cols); + + // Reset the last boost indicator + //cpi->last_boost = 100; + + if (tot_mbs) + gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] + cpi->recent_ref_frame_usage[ALTREF_FRAME]) * 100 / tot_mbs; + + if (pct_gf_active > gf_frame_useage) + gf_frame_useage = pct_gf_active; + + // Is a fixed manual GF frequency being used + if (!cpi->auto_gold) + cpi->common.refresh_golden_frame = TRUE; + else + { + // For one pass throw a GF if recent frame intra useage is low or the GF useage is high + if ((cpi->pass == 0) && (cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) + cpi->common.refresh_golden_frame = TRUE; + + // Two pass GF descision + else if (cpi->pass == 2) + cpi->common.refresh_golden_frame = TRUE; + } + +#if 0 + + // Debug stats + if (0) + { + FILE *f; + + f = fopen("gf_useaget.stt", "a"); + fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n", + cpi->common.current_video_frame, cpi->gfu_boost, GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage); + fclose(f); + } + +#endif + + if (cpi->common.refresh_golden_frame == TRUE) + { + int isize_adjustment = 0; +#if 0 + + if (0) // p_gw + { + FILE *f; + + f = fopen("GFexit.stt", "a"); + fprintf(f, "%8ld GF coded\n", cpi->common.current_video_frame); + fclose(f); + } + +#endif + cpi->initial_gf_use = 0; + + if (cpi->auto_adjust_gold_quantizer) + { + calc_gf_params(cpi); + } + + // If we are using alternate ref instead of gf then do not apply the boost + // It will instead be applied to the altref update + // Jims modified boost + if (!cpi->source_alt_ref_active) + { + if (cpi->oxcf.fixed_q < 0) + { + if (cpi->pass == 2) + { + cpi->this_frame_target = cpi->per_frame_bandwidth; // The spend on the GF is defined in the two pass code for two pass encodes + } + else + { + int Boost = cpi->last_boost; + int frames_in_section = cpi->frames_till_gf_update_due + 1; + int allocation_chunks = (frames_in_section * 100) + (Boost - 100); + int bits_in_section = cpi->inter_frame_target * frames_in_section; + + // Normalize Altboost and allocations chunck down to prevent overflow + while (Boost > 1000) + { + Boost /= 2; + allocation_chunks /= 2; + } + + // Avoid loss of precision but avoid overflow + if ((bits_in_section >> 7) > allocation_chunks) + cpi->this_frame_target = Boost * (bits_in_section / allocation_chunks); + else + cpi->this_frame_target = (Boost * bits_in_section) / allocation_chunks; + } + } + else + cpi->this_frame_target = (baseline_bits_at_q(1, Q, cpi->common.MBs) * cpi->last_boost) / 100; + + } + // If there is an active ARF at this location use the minimum bits on this frame + else + { + cpi->this_frame_target = 0; // Minimial spend on gf that is replacing an arf + } + + cpi->current_gf_interval = cpi->frames_till_gf_update_due; + + } + } +} + + +void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var) +{ + int Q = cpi->common.base_qindex; + int correction_factor = 100; + double rate_correction_factor; + double adjustment_limit; + + int projected_size_based_on_q = 0; + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); //__asm emms; + + if (cpi->common.frame_type == KEY_FRAME) + { + rate_correction_factor = cpi->key_frame_rate_correction_factor; + } + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + rate_correction_factor = cpi->gf_rate_correction_factor; + else + rate_correction_factor = cpi->rate_correction_factor; + } + + // Work out how big we would have expected the frame to be at this Q given the current correction factor. + // Stay in double to avoid int overflow when values are large + //projected_size_based_on_q = ((int)(.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) >> BPER_MB_NORMBITS; + projected_size_based_on_q = (int)(((.5 + rate_correction_factor * vp8_bits_per_mb[cpi->common.frame_type][Q]) * cpi->common.MBs) / (1 << BPER_MB_NORMBITS)); + + // Make some allowance for cpi->zbin_over_quant + if (cpi->zbin_over_quant > 0) + { + int Z = cpi->zbin_over_quant; + double Factor = 0.99; + double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; + + while (Z > 0) + { + Z --; + projected_size_based_on_q *= (int)Factor; + Factor += factor_adjustment; + + if (Factor >= 0.999) + Factor = 0.999; + } + } + + // Work out a size correction factor. + //if ( cpi->this_frame_target > 0 ) + // correction_factor = (100 * cpi->projected_frame_size) / cpi->this_frame_target; + if (projected_size_based_on_q > 0) + correction_factor = (100 * cpi->projected_frame_size) / projected_size_based_on_q; + + // More heavily damped adjustment used if we have been oscillating either side of target + switch (damp_var) + { + case 0: + adjustment_limit = 0.75; + break; + case 1: + adjustment_limit = 0.375; + break; + case 2: + default: + adjustment_limit = 0.25; + break; + } + + //if ( (correction_factor > 102) && (Q < cpi->active_worst_quality) ) + if (correction_factor > 102) + { + // We are not already at the worst allowable quality + correction_factor = (int)(100.5 + ((correction_factor - 100) * adjustment_limit)); + rate_correction_factor = ((rate_correction_factor * correction_factor) / 100); + + // Keep rate_correction_factor within limits + if (rate_correction_factor > MAX_BPB_FACTOR) + rate_correction_factor = MAX_BPB_FACTOR; + } + //else if ( (correction_factor < 99) && (Q > cpi->active_best_quality) ) + else if (correction_factor < 99) + { + // We are not already at the best allowable quality + correction_factor = (int)(100.5 - ((100 - correction_factor) * adjustment_limit)); + rate_correction_factor = ((rate_correction_factor * correction_factor) / 100); + + // Keep rate_correction_factor within limits + if (rate_correction_factor < MIN_BPB_FACTOR) + rate_correction_factor = MIN_BPB_FACTOR; + } + + if (cpi->common.frame_type == KEY_FRAME) + cpi->key_frame_rate_correction_factor = rate_correction_factor; + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + cpi->gf_rate_correction_factor = rate_correction_factor; + else + cpi->rate_correction_factor = rate_correction_factor; + } +} + +static int estimate_bits_at_q(VP8_COMP *cpi, int Q) +{ + int Bpm = (int)(.5 + cpi->rate_correction_factor * vp8_bits_per_mb[INTER_FRAME][Q]); + + /* Attempt to retain reasonable accuracy without overflow. The cutoff is + * chosen such that the maximum product of Bpm and MBs fits 31 bits. The + * largest Bpm takes 20 bits. + */ + if (cpi->common.MBs > (1 << 11)) + return (Bpm >> BPER_MB_NORMBITS) * cpi->common.MBs; + else + return (Bpm * cpi->common.MBs) >> BPER_MB_NORMBITS; + +} + + +int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) +{ + int Q = cpi->active_worst_quality; + + // Reset Zbin OQ value + cpi->zbin_over_quant = 0; + + if (cpi->oxcf.fixed_q >= 0) + { + Q = cpi->oxcf.fixed_q; + + if (cpi->common.frame_type == KEY_FRAME) + { + Q = cpi->oxcf.key_q; + } + else if (cpi->common.refresh_alt_ref_frame) + { + Q = cpi->oxcf.alt_q; + } + else if (cpi->common.refresh_golden_frame) + { + Q = cpi->oxcf.gold_q; + } + + } + else + { + int i; + int last_error = INT_MAX; + int target_bits_per_mb; + int bits_per_mb_at_this_q; + double correction_factor; + + // Select the appropriate correction factor based upon type of frame. + if (cpi->common.frame_type == KEY_FRAME) + correction_factor = cpi->key_frame_rate_correction_factor; + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + correction_factor = cpi->gf_rate_correction_factor; + else + correction_factor = cpi->rate_correction_factor; + } + + // Calculate required scaling factor based on target frame size and size of frame produced using previous Q + if (target_bits_per_frame >= (INT_MAX >> BPER_MB_NORMBITS)) + target_bits_per_mb = (target_bits_per_frame / cpi->common.MBs) << BPER_MB_NORMBITS; // Case where we would overflow int + else + target_bits_per_mb = (target_bits_per_frame << BPER_MB_NORMBITS) / cpi->common.MBs; + + i = cpi->active_best_quality; + + do + { + bits_per_mb_at_this_q = (int)(.5 + correction_factor * vp8_bits_per_mb[cpi->common.frame_type][i]); + + if (bits_per_mb_at_this_q <= target_bits_per_mb) + { + if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) + Q = i; + else + Q = i - 1; + + break; + } + else + last_error = bits_per_mb_at_this_q - target_bits_per_mb; + } + while (++i <= cpi->active_worst_quality); + + + // If we are at MAXQ then enable Q over-run which seeks to claw back additional bits through things like + // the RD multiplier and zero bin size. + if (Q >= MAXQ) + { + int zbin_oqmax; + + double Factor = 0.99; + double factor_adjustment = 0.01 / 256.0; //(double)ZBIN_OQ_MAX; + + if (cpi->common.frame_type == KEY_FRAME) + zbin_oqmax = 0; //ZBIN_OQ_MAX/16 + else if (cpi->common.refresh_alt_ref_frame || (cpi->common.refresh_golden_frame && !cpi->source_alt_ref_active)) + zbin_oqmax = 16; + else + zbin_oqmax = ZBIN_OQ_MAX; + + /*{ + double Factor = (double)target_bits_per_mb/(double)bits_per_mb_at_this_q; + double Oq; + + Factor = Factor/1.2683; + + Oq = pow( Factor, (1.0/-0.165) ); + + if ( Oq > zbin_oqmax ) + Oq = zbin_oqmax; + + cpi->zbin_over_quant = (int)Oq; + }*/ + + // Each incrment in the zbin is assumed to have a fixed effect on bitrate. This is not of course true. + // The effect will be highly clip dependent and may well have sudden steps. + // The idea here is to acheive higher effective quantizers than the normal maximum by expanding the zero + // bin and hence decreasing the number of low magnitude non zero coefficients. + while (cpi->zbin_over_quant < zbin_oqmax) + { + cpi->zbin_over_quant ++; + + if (cpi->zbin_over_quant > zbin_oqmax) + cpi->zbin_over_quant = zbin_oqmax; + + bits_per_mb_at_this_q *= (int)Factor; // Each over-ruin step is assumed to equate to approximately 3% reduction in bitrate + Factor += factor_adjustment; + + if (Factor >= 0.999) + Factor = 0.999; + + if (bits_per_mb_at_this_q <= target_bits_per_mb) // Break out if we get down to the target rate + break; + } + + } + } + + return Q; +} + +static int estimate_min_frame_size(VP8_COMP *cpi) +{ + double correction_factor; + int bits_per_mb_at_max_q; + + // This funtion returns a default value for the first few frames untill the correction factor has had time to adapt. + if (cpi->common.current_video_frame < 10) + { + if (cpi->pass == 2) + return (cpi->min_frame_bandwidth); + else + return cpi->per_frame_bandwidth / 3; + } + + /* // Select the appropriate correction factor based upon type of frame. + if ( cpi->common.frame_type == KEY_FRAME ) + correction_factor = cpi->key_frame_rate_correction_factor; + else + { + if ( cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame ) + correction_factor = cpi->gf_rate_correction_factor; + else + correction_factor = cpi->rate_correction_factor; + }*/ + + // We estimate at half the value we get from vp8_bits_per_mb + correction_factor = cpi->rate_correction_factor / 2.0; + + bits_per_mb_at_max_q = (int)(.5 + correction_factor * vp8_bits_per_mb[cpi->common.frame_type][MAXQ]); + + return (bits_per_mb_at_max_q * cpi->common.MBs) >> BPER_MB_NORMBITS; +} + +void vp8_adjust_key_frame_context(VP8_COMP *cpi) +{ + int i; + int av_key_frames_per_second; + + // Average key frame frequency and size + unsigned int total_weight = 0; + unsigned int av_key_frame_frequency = 0; + unsigned int av_key_frame_bits = 0; + + unsigned int output_frame_rate = (unsigned int)(100 * cpi->output_frame_rate); + unsigned int target_bandwidth = (unsigned int)(100 * cpi->target_bandwidth); + + // Clear down mmx registers to allow floating point in what follows + vp8_clear_system_state(); //__asm emms; + + // Update the count of total key frame bits + cpi->tot_key_frame_bits += cpi->projected_frame_size; + + // First key frame at start of sequence is a special case. We have no frequency data. + if (cpi->key_frame_count == 1) + { + av_key_frame_frequency = (int)cpi->output_frame_rate * 2; // Assume a default of 1 kf every 2 seconds + av_key_frame_bits = cpi->projected_frame_size; + av_key_frames_per_second = output_frame_rate / av_key_frame_frequency; // Note output_frame_rate not cpi->output_frame_rate + } + else + { + // reset keyframe context and calculate weighted average of last KEY_FRAME_CONTEXT keyframes + for (i = 0; i < KEY_FRAME_CONTEXT; i++) + { + if (i < KEY_FRAME_CONTEXT - 1) + { + cpi->prior_key_frame_size[i] = cpi->prior_key_frame_size[i+1]; + cpi->prior_key_frame_distance[i] = cpi->prior_key_frame_distance[i+1]; + } + else + { + cpi->prior_key_frame_size[KEY_FRAME_CONTEXT - 1] = cpi->projected_frame_size; + cpi->prior_key_frame_distance[KEY_FRAME_CONTEXT - 1] = cpi->frames_since_key; + } + + av_key_frame_bits += prior_key_frame_weight[i] * cpi->prior_key_frame_size[i]; + av_key_frame_frequency += prior_key_frame_weight[i] * cpi->prior_key_frame_distance[i]; + total_weight += prior_key_frame_weight[i]; + } + + av_key_frame_bits /= total_weight; + av_key_frame_frequency /= total_weight; + av_key_frames_per_second = output_frame_rate / av_key_frame_frequency; + + } + + // Do we have any key frame overspend to recover? + if ((cpi->pass != 2) && (cpi->projected_frame_size > cpi->per_frame_bandwidth)) + { + // Update the count of key frame overspend to be recovered in subsequent frames + // A portion of the KF overspend is treated as gf overspend (and hence recovered more quickly) + // as the kf is also a gf. Otherwise the few frames following each kf tend to get more bits + // allocated than those following other gfs. + cpi->kf_overspend_bits += (cpi->projected_frame_size - cpi->per_frame_bandwidth) * 7 / 8; + cpi->gf_overspend_bits += (cpi->projected_frame_size - cpi->per_frame_bandwidth) * 1 / 8; + + // Work out how much to try and recover per frame. + // For one pass we estimate the number of frames to spread it over based upon past history. + // For two pass we know how many frames there will be till the next kf. + if (cpi->pass == 2) + { + if (cpi->frames_to_key > 16) + cpi->kf_bitrate_adjustment = cpi->kf_overspend_bits / (int)cpi->frames_to_key; + else + cpi->kf_bitrate_adjustment = cpi->kf_overspend_bits / 16; + } + else + cpi->kf_bitrate_adjustment = cpi->kf_overspend_bits / (int)av_key_frame_frequency; + } + + cpi->frames_since_key = 0; + cpi->last_key_frame_size = cpi->projected_frame_size; + cpi->key_frame_count++; +} + +void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, int *frame_over_shoot_limit) +{ + // Set-up bounds on acceptable frame size: + if (cpi->oxcf.fixed_q >= 0) + { + // Fixed Q scenario: frame size never outranges target (there is no target!) + *frame_under_shoot_limit = 0; + *frame_over_shoot_limit = INT_MAX; + } + else + { + if (cpi->common.frame_type == KEY_FRAME) + { + *frame_over_shoot_limit = cpi->this_frame_target * 9 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 7 / 8; + } + else + { + if (cpi->common.refresh_alt_ref_frame || cpi->common.refresh_golden_frame) + { + *frame_over_shoot_limit = cpi->this_frame_target * 9 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 7 / 8; + } + else + { + // For CBR take buffer fullness into account + if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) + { + if (cpi->buffer_level >= ((cpi->oxcf.optimal_buffer_level + cpi->oxcf.maximum_buffer_size) >> 1)) + { + // Buffer is too full so relax overshoot and tighten undershoot + *frame_over_shoot_limit = cpi->this_frame_target * 12 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 6 / 8; + } + else if (cpi->buffer_level <= (cpi->oxcf.optimal_buffer_level >> 1)) + { + // Buffer is too low so relax undershoot and tighten overshoot + *frame_over_shoot_limit = cpi->this_frame_target * 10 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 4 / 8; + } + else + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + } + } + // VBR + // Note that tighter restrictions here can help quality but hurt encode speed + else + { + *frame_over_shoot_limit = cpi->this_frame_target * 11 / 8; + *frame_under_shoot_limit = cpi->this_frame_target * 5 / 8; + } + } + } + } +}
diff --git a/vp8/encoder/ratectrl.h b/vp8/encoder/ratectrl.h new file mode 100644 index 0000000..588c7a8 --- /dev/null +++ b/vp8/encoder/ratectrl.h
@@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#if !defined __INC_RATECTRL_H + +#include "onyx_int.h" + +extern void vp8_save_coding_context(VP8_COMP *cpi); +extern void vp8_restore_coding_context(VP8_COMP *cpi); + +extern void vp8_setup_key_frame(VP8_COMP *cpi); +extern void vp8_calc_iframe_target_size(VP8_COMP *cpi); +extern void vp8_calc_pframe_target_size(VP8_COMP *cpi); +extern void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var); +extern int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame); +extern void vp8_adjust_key_frame_context(VP8_COMP *cpi); +extern void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, int *frame_over_shoot_limit); + +#endif
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c new file mode 100644 index 0000000..0846996 --- /dev/null +++ b/vp8/encoder/rdopt.c
@@ -0,0 +1,2212 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdio.h> +#include <math.h> +#include <limits.h> +#include <assert.h> +#include "pragmas.h" + +#include "tokenize.h" +#include "treewriter.h" +#include "onyx_int.h" +#include "modecosts.h" +#include "encodeintra.h" +#include "entropymode.h" +#include "reconinter.h" +#include "reconintra.h" +#include "reconintra4x4.h" +#include "findnearmv.h" +#include "encodemb.h" +#include "quantize.h" +#include "idct.h" +#include "g_common.h" +#include "variance.h" +#include "mcomp.h" + +#include "vpx_mem/vpx_mem.h" +#include "dct.h" +#include "systemdependent.h" + +#define DIAMONDSEARCH 1 +#if CONFIG_RUNTIME_CPU_DETECT +#define IF_RTCD(x) (x) +#else +#define IF_RTCD(x) NULL +#endif + + +void vp8cx_mb_init_quantizer(VP8_COMP *cpi, MACROBLOCK *x); + + +#define RDFUNC(RM,DM,R,D,target_rd) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) +/*int RDFUNC( int RM,int DM, int R, int D, int target_r ) +{ + int rd_value; + + rd_value = ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ); + + return rd_value; +}*/ + +#define UVRDFUNC(RM,DM,R,D,target_r) RDFUNC(RM,DM,R,D,target_r) + +#define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) + +#define MAXF(a,b) (((a) > (b)) ? (a) : (b)) + + +extern const TOKENEXTRA vp8_dct_value_tokens[DCT_MAX_VALUE*2]; +extern const TOKENEXTRA *vp8_dct_value_tokens_ptr; +extern int vp8_dct_value_cost[DCT_MAX_VALUE*2]; +extern int *vp8_dct_value_cost_ptr; + + +const int vp8_auto_speed_thresh[17] = +{ + 1000, + 200, + 150, + 130, + 150, + 125, + 120, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 115, + 105 +}; + +const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES] = +{ + ZEROMV, + DC_PRED, + + NEARESTMV, + NEARMV, + + ZEROMV, + NEARESTMV, + + ZEROMV, + NEARESTMV, + + NEARMV, + NEARMV, + + V_PRED, + H_PRED, + TM_PRED, + + NEWMV, + NEWMV, + NEWMV, + + SPLITMV, + SPLITMV, + SPLITMV, + + B_PRED, +}; + +const MV_REFERENCE_FRAME vp8_ref_frame_order[MAX_MODES] = +{ + LAST_FRAME, + INTRA_FRAME, + + LAST_FRAME, + LAST_FRAME, + + GOLDEN_FRAME, + GOLDEN_FRAME, + + ALTREF_FRAME, + ALTREF_FRAME, + + GOLDEN_FRAME, + ALTREF_FRAME, + + INTRA_FRAME, + INTRA_FRAME, + INTRA_FRAME, + + LAST_FRAME, + GOLDEN_FRAME, + ALTREF_FRAME, + + LAST_FRAME, + GOLDEN_FRAME, + ALTREF_FRAME, + + INTRA_FRAME, +}; + +static void fill_token_costs( + unsigned int c [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens], + const vp8_prob p [BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens-1] +) +{ + int i, j, k; + + + for (i = 0; i < BLOCK_TYPES; i++) + for (j = 0; j < COEF_BANDS; j++) + for (k = 0; k < PREV_COEF_CONTEXTS; k++) + + vp8_cost_tokens((int *)(c [i][j][k]), p [i][j][k], vp8_coef_tree); + +} + +static int rd_iifactor [ 32 ] = { 16, 16, 16, 12, 8, 4, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + + + +// The values in this table should be reviewed +static int sad_per_bit16lut[128] = +{ + 4, 4, 4, 4, 4, 4, 4, 4, // 4 + 4, 4, 4, 4, 4, 4, 4, 4, // 1 + 4, 4, 4, 4, 4, 4, 4, 4, // 2 + 4, 4, 4, 4, 4, 4, 4, 4, // 3 + 4, 4, 4, 4, 4, 4, 4, 4, // 4 + 4, 4, 12, 12, 13, 13, 14, 14, // 5 + 14, 14, 14, 15, 15, 15, 15, 15, // 6 + 15, 15, 15, 15, 15, 15, 15, 15, // 7 + 15, 15, 15, 15, 15, 16, 16, 16, // 8 + 16, 16, 18, 18, 18, 18, 19, 19, // 9 + 19, 19, 19, 19, 19, 19, 19, 19, // 10 + 20, 20, 22, 22, 22, 22, 21, 21, // 11 + 22, 22, 22, 22, 22, 22, 22, 22, // 12 + 22, 22, 22, 22, 22, 22, 22, 22, // 13 + 22, 22, 22, 22, 22, 22, 22, 22, // 14 + 22, 22, 22, 22, 22, 22, 22, 22, // 15 +}; + +static int sad_per_bit4lut[128] = +{ + 4, 4, 4, 4, 4, 4, 4, 4, // 4 + 4, 4, 4, 4, 4, 4, 4, 4, // 1 + 4, 4, 4, 4, 4, 4, 4, 4, // 2 + 4, 4, 4, 4, 4, 4, 4, 4, // 3 + 4, 4, 4, 4, 4, 4, 4, 4, // 4 + 4, 4, 15, 15, 15, 15, 16, 16, // 5 + 16, 17, 17, 17, 17, 17, 17, 17, // 6 + 17, 17, 19, 19, 22, 22, 21, 21, // 7 + 23, 23, 23, 23, 23, 24, 24, 24, // 8 + 25, 25, 27, 27, 27, 27, 28, 28, // 9 + 28, 28, 29, 29, 29, 29, 29, 29, // 10 + 30, 30, 31, 31, 31, 31, 32, 32, // 11 + 34, 34, 34, 34, 34, 34, 34, 34, // 12 + 34, 34, 34, 34, 34, 34, 34, 34, // 13 + 34, 34, 34, 34, 34, 34, 34, 34, // 14 + 34, 34, 34, 34, 34, 34, 34, 34, // 15 +}; + +void vp8cx_initialize_me_consts(VP8_COMP *cpi, int QIndex) +{ + cpi->mb.sadperbit16 = sad_per_bit16lut[QIndex]; + cpi->mb.sadperbit4 = sad_per_bit4lut[QIndex]; +} + +void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue) +{ + int q; + int i; + int *thresh; + int threshmult; + + int capped_q = (Qvalue < 160) ? Qvalue : 160; + + vp8_clear_system_state(); //__asm emms; + + cpi->RDMULT = (int)((0.00007 * (capped_q * capped_q * capped_q * capped_q)) - (0.0125 * (capped_q * capped_q * capped_q)) + + (2.25 * (capped_q * capped_q)) - (12.5 * capped_q) + 25.0); + + if (cpi->RDMULT < 25) + cpi->RDMULT = 25; + + if (cpi->pass == 2) + { + if (cpi->common.frame_type == KEY_FRAME) + cpi->RDMULT += (cpi->RDMULT * rd_iifactor[0]) / 16; + else if (cpi->next_iiratio > 31) + cpi->RDMULT += (cpi->RDMULT * rd_iifactor[31]) / 16; + else + cpi->RDMULT += (cpi->RDMULT * rd_iifactor[cpi->next_iiratio]) / 16; + } + + + // Extend rate multiplier along side quantizer zbin increases + if (cpi->zbin_over_quant > 0) + { + // Extend rate multiplier along side quantizer zbin increases + if (cpi->zbin_over_quant > 0) + { + double oq_factor = pow(1.006, cpi->zbin_over_quant); + + if (oq_factor > (1.0 + ((double)cpi->zbin_over_quant / 64.0))) + oq_factor = (1.0 + (double)cpi->zbin_over_quant / 64.0); + + cpi->RDMULT *= (int)oq_factor; + } + } + + cpi->mb.errorperbit = (cpi->RDMULT / 100); + + if (cpi->mb.errorperbit < 1) + cpi->mb.errorperbit = 1; + + vp8_set_speed_features(cpi); + + if (cpi->common.simpler_lpf) + cpi->common.filter_type = SIMPLE_LOOPFILTER; + + q = (int)pow(Qvalue, 1.25); + + if (q < 8) + q = 8; + + if (cpi->ref_frame_flags == VP8_ALT_FLAG) + { + thresh = &cpi->rd_threshes[THR_NEWA]; + threshmult = cpi->sf.thresh_mult[THR_NEWA]; + } + else if (cpi->ref_frame_flags == VP8_GOLD_FLAG) + { + thresh = &cpi->rd_threshes[THR_NEWG]; + threshmult = cpi->sf.thresh_mult[THR_NEWG]; + } + else + { + thresh = &cpi->rd_threshes[THR_NEWMV]; + threshmult = cpi->sf.thresh_mult[THR_NEWMV]; + } + + if (cpi->RDMULT > 1000) + { + cpi->RDDIV = 1; + cpi->RDMULT /= 100; + + for (i = 0; i < MAX_MODES; i++) + { + if (cpi->sf.thresh_mult[i] < INT_MAX) + { + cpi->rd_threshes[i] = cpi->sf.thresh_mult[i] * q / 100; + } + else + { + cpi->rd_threshes[i] = INT_MAX; + } + + cpi->rd_baseline_thresh[i] = cpi->rd_threshes[i]; + } + } + else + { + cpi->RDDIV = 100; + + for (i = 0; i < MAX_MODES; i++) + { + if (cpi->sf.thresh_mult[i] < (INT_MAX / q)) + { + cpi->rd_threshes[i] = cpi->sf.thresh_mult[i] * q; + } + else + { + cpi->rd_threshes[i] = INT_MAX; + } + + cpi->rd_baseline_thresh[i] = cpi->rd_threshes[i]; + } + } + + fill_token_costs( + cpi->mb.token_costs, + (const vp8_prob( *)[8][3][11]) cpi->common.fc.coef_probs + ); + + vp8_init_mode_costs(cpi); + +} + +void vp8_auto_select_speed(VP8_COMP *cpi) +{ + int used = cpi->oxcf.cpu_used; + + int milliseconds_for_compress = (int)(1000000 / cpi->oxcf.frame_rate); + + milliseconds_for_compress = milliseconds_for_compress * (16 - cpi->oxcf.cpu_used) / 16; + +#if 0 + + if (0) + { + FILE *f; + + f = fopen("speed.stt", "a"); + fprintf(f, " %8ld %10ld %10ld %10ld\n", + cpi->common.current_video_frame, cpi->Speed, milliseconds_for_compress, cpi->avg_pick_mode_time); + fclose(f); + } + +#endif + + /* + // this is done during parameter valid check + if( used > 16) + used = 16; + if( used < -16) + used = -16; + */ + + if (cpi->avg_pick_mode_time < milliseconds_for_compress && (cpi->avg_encode_time - cpi->avg_pick_mode_time) < milliseconds_for_compress) + { + if (cpi->avg_pick_mode_time == 0) + { + cpi->Speed = 4; + } + else + { + if (milliseconds_for_compress * 100 < cpi->avg_encode_time * 95) + { + cpi->Speed += 2; + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + + if (cpi->Speed > 16) + { + cpi->Speed = 16; + } + } + + if (milliseconds_for_compress * 100 > cpi->avg_encode_time * vp8_auto_speed_thresh[cpi->Speed]) + { + cpi->Speed -= 1; + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + + // In real-time mode, cpi->speed is in [4, 16]. + if (cpi->Speed < 4) //if ( cpi->Speed < 0 ) + { + cpi->Speed = 4; //cpi->Speed = 0; + } + } + } + } + else + { + cpi->Speed += 4; + + if (cpi->Speed > 16) + cpi->Speed = 16; + + + cpi->avg_pick_mode_time = 0; + cpi->avg_encode_time = 0; + } +} + +int vp8_block_error_c(short *coeff, short *dqcoeff) +{ + int i; + int error = 0; + + for (i = 0; i < 16; i++) + { + int this_diff = coeff[i] - dqcoeff[i]; + error += this_diff * this_diff; + } + + return error; +} + +int vp8_mbblock_error_c(MACROBLOCK *mb, int dc) +{ + BLOCK *be; + BLOCKD *bd; + int i, j; + int berror, error = 0; + + for (i = 0; i < 16; i++) + { + be = &mb->block[i]; + bd = &mb->e_mbd.block[i]; + + berror = 0; + + for (j = dc; j < 16; j++) + { + int this_diff = be->coeff[j] - bd->dqcoeff[j]; + berror += this_diff * this_diff; + } + + error += berror; + } + + return error; +} + +int vp8_mbuverror_c(MACROBLOCK *mb) +{ + + BLOCK *be; + BLOCKD *bd; + + + int i; + int error = 0; + + for (i = 16; i < 24; i++) + { + be = &mb->block[i]; + bd = &mb->e_mbd.block[i]; + + error += vp8_block_error_c(be->coeff, bd->dqcoeff); + } + + return error; +} + +#if !(CONFIG_REALTIME_ONLY) +static int macro_block_max_error(MACROBLOCK *mb) +{ + int error = 0; + int dc = 0; + BLOCK *be; + int i, j; + int berror; + + dc = !(mb->e_mbd.mbmi.mode == B_PRED || mb->e_mbd.mbmi.mode == SPLITMV); + + for (i = 0; i < 16; i++) + { + be = &mb->block[i]; + + berror = 0; + + for (j = dc; j < 16; j++) + { + int this_diff = be->coeff[j]; + berror += this_diff * this_diff; + } + + error += berror; + } + + for (i = 16; i < 24; i++) + { + be = &mb->block[i]; + berror = 0; + + for (j = 0; j < 16; j++) + { + int this_diff = be->coeff[j]; + berror += this_diff * this_diff; + } + + error += berror; + } + + error <<= 2; + + if (dc) + { + be = &mb->block[24]; + berror = 0; + + for (j = 0; j < 16; j++) + { + int this_diff = be->coeff[j]; + berror += this_diff * this_diff; + } + + error += berror; + } + + error >>= 4; + return error; +} +#endif + +int VP8_UVSSE(MACROBLOCK *x, const vp8_variance_rtcd_vtable_t *rtcd) +{ + unsigned char *uptr, *vptr; + unsigned char *upred_ptr = (*(x->block[16].base_src) + x->block[16].src); + unsigned char *vpred_ptr = (*(x->block[20].base_src) + x->block[20].src); + int uv_stride = x->block[16].src_stride; + + unsigned int sse1 = 0; + unsigned int sse2 = 0; + int mv_row; + int mv_col; + int offset; + int pre_stride = x->e_mbd.block[16].pre_stride; + + vp8_build_uvmvs(&x->e_mbd, 0); + mv_row = x->e_mbd.block[16].bmi.mv.as_mv.row; + mv_col = x->e_mbd.block[16].bmi.mv.as_mv.col; + + offset = (mv_row >> 3) * pre_stride + (mv_col >> 3); + uptr = x->e_mbd.pre.u_buffer + offset; + vptr = x->e_mbd.pre.v_buffer + offset; + + if ((mv_row | mv_col) & 7) + { + VARIANCE_INVOKE(rtcd, subpixvar8x8)(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, uv_stride, &sse2); + VARIANCE_INVOKE(rtcd, subpixvar8x8)(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, uv_stride, &sse1); + sse2 += sse1; + } + else + { + VARIANCE_INVOKE(rtcd, subpixvar8x8)(uptr, pre_stride, mv_col & 7, mv_row & 7, upred_ptr, uv_stride, &sse2); + VARIANCE_INVOKE(rtcd, subpixvar8x8)(vptr, pre_stride, mv_col & 7, mv_row & 7, vpred_ptr, uv_stride, &sse1); + sse2 += sse1; + } + + return sse2; + +} + +#if !(CONFIG_REALTIME_ONLY) +static int cost_coeffs(MACROBLOCK *mb, BLOCKD *b, int type, ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) +{ + int c = !type; /* start at coef 0, unless Y with Y2 */ + int eob = b->eob; + int pt ; /* surrounding block/prev coef predictor */ + int cost = 0; + short *qcoeff_ptr = b->qcoeff; + + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + +# define QC( I) ( qcoeff_ptr [vp8_default_zig_zag1d[I]] ) + + for (; c < eob; c++) + { + int v = QC(c); + int t = vp8_dct_value_tokens_ptr[v].Token; + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [t]; + cost += vp8_dct_value_cost_ptr[v]; + pt = vp8_prev_token_class[t]; + } + +# undef QC + + if (c < 16) + cost += mb->token_costs [type] [vp8_coef_bands[c]] [pt] [DCT_EOB_TOKEN]; + + pt = (c != !type); // is eob first coefficient; + *a = *l = pt; + + return cost; +} + +int vp8_rdcost_mby(MACROBLOCK *mb) +{ + int cost = 0; + int b; + TEMP_CONTEXT t, t2; + int type = 0; + + MACROBLOCKD *x = &mb->e_mbd; + + vp8_setup_temp_context(&t, x->above_context[Y1CONTEXT], x->left_context[Y1CONTEXT], 4); + vp8_setup_temp_context(&t2, x->above_context[Y2CONTEXT], x->left_context[Y2CONTEXT], 1); + + if (x->mbmi.mode == SPLITMV) + type = 3; + + for (b = 0; b < 16; b++) + cost += cost_coeffs(mb, x->block + b, type, + t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + + if (x->mbmi.mode != SPLITMV) + cost += cost_coeffs(mb, x->block + 24, 1, + t2.a + vp8_block2above[24], t2.l + vp8_block2left[24]); + + return cost; +} + + +static void rd_pick_intra4x4block( + VP8_COMP *cpi, + MACROBLOCK *x, + BLOCK *be, + BLOCKD *b, + B_PREDICTION_MODE *best_mode, + B_PREDICTION_MODE above, + B_PREDICTION_MODE left, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + + int *bestrate, + int *bestratey, + int *bestdistortion) +{ + B_PREDICTION_MODE mode; + int best_rd = INT_MAX; // 1<<30 + int rate = 0; + int distortion; + unsigned int *mode_costs; + + ENTROPY_CONTEXT ta = *a, tempa = *a; + ENTROPY_CONTEXT tl = *l, templ = *l; + + + if (x->e_mbd.frame_type == KEY_FRAME) + { + mode_costs = x->bmode_costs[above][left]; + } + else + { + mode_costs = x->inter_bmode_costs; + } + + for (mode = B_DC_PRED; mode <= B_HU_PRED; mode++) + { + int this_rd; + int ratey; + + rate = mode_costs[mode]; + vp8_encode_intra4x4block_rd(IF_RTCD(&cpi->rtcd), x, be, b, mode); + + tempa = ta; + templ = tl; + + ratey = cost_coeffs(x, b, 3, &tempa, &templ); + rate += ratey; + distortion = ENCODEMB_INVOKE(IF_RTCD(&cpi->rtcd.encodemb), berr)(be->coeff, b->dqcoeff) >> 2; + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + *bestrate = rate; + *bestratey = ratey; + *bestdistortion = distortion; + best_rd = this_rd; + *best_mode = mode; + *a = tempa; + *l = templ; + } + } + + b->bmi.mode = (B_PREDICTION_MODE)(*best_mode); + vp8_encode_intra4x4block_rd(IF_RTCD(&cpi->rtcd), x, be, b, b->bmi.mode); + +} + + +int vp8_rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate, int *rate_y, int *Distortion) +{ + MACROBLOCKD *const xd = &mb->e_mbd; + int i; + TEMP_CONTEXT t; + int cost = mb->mbmode_cost [xd->frame_type] [B_PRED]; + int distortion = 0; + int tot_rate_y = 0; + + vp8_intra_prediction_down_copy(xd); + vp8_setup_temp_context(&t, xd->above_context[Y1CONTEXT], xd->left_context[Y1CONTEXT], 4); + + for (i = 0; i < 16; i++) + { + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + const B_PREDICTION_MODE A = vp8_above_bmi(mic, i, mis)->mode; + const B_PREDICTION_MODE L = vp8_left_bmi(mic, i)->mode; + B_PREDICTION_MODE UNINITIALIZED_IS_SAFE(best_mode); + int UNINITIALIZED_IS_SAFE(r), UNINITIALIZED_IS_SAFE(ry), UNINITIALIZED_IS_SAFE(d); + + rd_pick_intra4x4block( + cpi, mb, mb->block + i, xd->block + i, &best_mode, A, L, + t.a + vp8_block2above[i], + t.l + vp8_block2left[i], &r, &ry, &d); + + cost += r; + distortion += d; + tot_rate_y += ry; + mic->bmi[i].mode = xd->block[i].bmi.mode = best_mode; + } + + *Rate = cost; + *rate_y += tot_rate_y; + *Distortion = distortion; + + return RDCOST(mb->rdmult, mb->rddiv, cost, distortion); +} + +int vp8_rd_pick_intra16x16mby_mode(VP8_COMP *cpi, MACROBLOCK *x, int *Rate, int *rate_y, int *Distortion) +{ + + MB_PREDICTION_MODE mode; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); + int rate, ratey; + unsigned int distortion; + int best_rd = INT_MAX; + + //Y Search for 16x16 intra prediction mode + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + int this_rd; + int dummy; + rate = 0; + + x->e_mbd.mbmi.mode = mode; + + rate += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mbmi.mode]; + + vp8_encode_intra16x16mbyrd(IF_RTCD(&cpi->rtcd), x); + + ratey = vp8_rdcost_mby(x); + + rate += ratey; + + VARIANCE_INVOKE(&cpi->rtcd.variance, get16x16var)(x->src.y_buffer, x->src.y_stride, x->e_mbd.dst.y_buffer, x->e_mbd.dst.y_stride, &distortion, &dummy); + + this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion); + + if (this_rd < best_rd) + { + mode_selected = mode; + best_rd = this_rd; + *Rate = rate; + *rate_y = ratey; + *Distortion = (int)distortion; + } + } + + x->e_mbd.mbmi.mode = mode_selected; + return best_rd; +} + + +static int rd_cost_mbuv(MACROBLOCK *mb) +{ + TEMP_CONTEXT t, t2; + int b; + int cost = 0; + MACROBLOCKD *x = &mb->e_mbd; + + vp8_setup_temp_context(&t, x->above_context[UCONTEXT], x->left_context[UCONTEXT], 2); + vp8_setup_temp_context(&t2, x->above_context[VCONTEXT], x->left_context[VCONTEXT], 2); + + for (b = 16; b < 20; b++) + cost += cost_coeffs(mb, x->block + b, vp8_block2type[b], + t.a + vp8_block2above[b], t.l + vp8_block2left[b]); + + for (b = 20; b < 24; b++) + cost += cost_coeffs(mb, x->block + b, vp8_block2type[b], + t2.a + vp8_block2above[b], t2.l + vp8_block2left[b]); + + return cost; +} + + +unsigned int vp8_get_mbuvrecon_error(const vp8_variance_rtcd_vtable_t *rtcd, const MACROBLOCK *x) // sum of squares +{ + unsigned int sse0, sse1; + int sum0, sum1; + VARIANCE_INVOKE(rtcd, get8x8var)(x->src.u_buffer, x->src.uv_stride, x->e_mbd.dst.u_buffer, x->e_mbd.dst.uv_stride, &sse0, &sum0); + VARIANCE_INVOKE(rtcd, get8x8var)(x->src.v_buffer, x->src.uv_stride, x->e_mbd.dst.v_buffer, x->e_mbd.dst.uv_stride, &sse1, &sum1); + return (sse0 + sse1); +} + +static int vp8_rd_inter_uv(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *distortion, int fullpixel) +{ + vp8_build_uvmvs(&x->e_mbd, fullpixel); + vp8_encode_inter16x16uvrd(IF_RTCD(&cpi->rtcd), x); + + + *rate = rd_cost_mbuv(x); + *distortion = ENCODEMB_INVOKE(&cpi->rtcd.encodemb, mbuverr)(x) / 4; + + return UVRDFUNC(x->rdmult, x->rddiv, *rate, *distortion, cpi->target_bits_per_mb); +} + +int vp8_rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *rate_tokenonly, int *distortion) +{ + MB_PREDICTION_MODE mode; + MB_PREDICTION_MODE UNINITIALIZED_IS_SAFE(mode_selected); + int best_rd = INT_MAX; + int UNINITIALIZED_IS_SAFE(d), UNINITIALIZED_IS_SAFE(r); + int rate_to; + + for (mode = DC_PRED; mode <= TM_PRED; mode++) + { + int rate; + int distortion; + int this_rd; + + x->e_mbd.mbmi.uv_mode = mode; + vp8_encode_intra16x16mbuvrd(IF_RTCD(&cpi->rtcd), x); + + rate_to = rd_cost_mbuv(x); + rate = rate_to + x->intra_uv_mode_cost[x->e_mbd.frame_type][x->e_mbd.mbmi.uv_mode]; + + distortion = vp8_get_mbuvrecon_error(IF_RTCD(&cpi->rtcd.variance), x); + + this_rd = UVRDFUNC(x->rdmult, x->rddiv, rate, distortion, cpi->target_bits_per_mb); + + if (this_rd < best_rd) + { + best_rd = this_rd; + d = distortion; + r = rate; + *rate_tokenonly = rate_to; + mode_selected = mode; + } + } + + *rate = r; + *distortion = d; + + x->e_mbd.mbmi.uv_mode = mode_selected; + return best_rd; +} +#endif + +int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]) +{ + vp8_prob p [VP8_MVREFS-1]; + assert(NEARESTMV <= m && m <= SPLITMV); + vp8_mv_ref_probs(p, near_mv_ref_ct); + return vp8_cost_token(vp8_mv_ref_tree, p, VP8_MVREFENCODINGS + m); +} + +void vp8_set_mbmode_and_mvs(MACROBLOCK *x, MB_PREDICTION_MODE mb, MV *mv) +{ + int i; + + x->e_mbd.mbmi.mode = mb; + x->e_mbd.mbmi.mv.as_mv.row = mv->row; + x->e_mbd.mbmi.mv.as_mv.col = mv->col; + + for (i = 0; i < 16; i++) + { + B_MODE_INFO *bmi = &x->e_mbd.block[i].bmi; + bmi->mode = (B_PREDICTION_MODE) mb; + bmi->mv.as_mv.row = mv->row; + bmi->mv.as_mv.col = mv->col; + } +} + +#if !(CONFIG_REALTIME_ONLY) +int vp8_count_labels(int const *labelings) +{ + int i; + int count = 0; + + for (i = 0; i < 16; i++) + { + if (labelings[i] > count) + count = labelings[i]; + } + + return count + 1; +} + + +static int labels2mode( + MACROBLOCK *x, + int const *labelings, int which_label, + B_PREDICTION_MODE this_mode, + MV *this_mv, MV *best_ref_mv, + int *mvcost[2] +) +{ + MACROBLOCKD *const xd = & x->e_mbd; + MODE_INFO *const mic = xd->mode_info_context; + const int mis = xd->mode_info_stride; + + int cost = 0; + int thismvcost = 0; + + /* We have to be careful retrieving previously-encoded motion vectors. + Ones from this macroblock have to be pulled from the BLOCKD array + as they have not yet made it to the bmi array in our MB_MODE_INFO. */ + + int i = 0; + + do + { + BLOCKD *const d = xd->block + i; + const int row = i >> 2, col = i & 3; + + B_PREDICTION_MODE m; + + if (labelings[i] != which_label) + continue; + + if (col && labelings[i] == labelings[i-1]) + m = LEFT4X4; + else if (row && labelings[i] == labelings[i-4]) + m = ABOVE4X4; + else + { + // the only time we should do costing for new motion vector or mode + // is when we are on a new label (jbb May 08, 2007) + switch (m = this_mode) + { + case NEW4X4 : + thismvcost = vp8_mv_bit_cost(this_mv, best_ref_mv, mvcost, 102); + break; + case LEFT4X4: + *this_mv = col ? d[-1].bmi.mv.as_mv : vp8_left_bmi(mic, i)->mv.as_mv; + break; + case ABOVE4X4: + *this_mv = row ? d[-4].bmi.mv.as_mv : vp8_above_bmi(mic, i, mis)->mv.as_mv; + break; + case ZERO4X4: + this_mv->row = this_mv->col = 0; + break; + default: + break; + } + + if (m == ABOVE4X4) // replace above with left if same + { + const MV mv = col ? d[-1].bmi.mv.as_mv : vp8_left_bmi(mic, i)->mv.as_mv; + + if (mv.row == this_mv->row && mv.col == this_mv->col) + m = LEFT4X4; + } + + cost = x->inter_bmode_costs[ m]; + } + + d->bmi.mode = m; + d->bmi.mv.as_mv = *this_mv; + + } + while (++i < 16); + + cost += thismvcost ; + return cost; +} + +static int rdcost_mbsegment_y(MACROBLOCK *mb, const int *labels, int which_label, TEMP_CONTEXT *t) +{ + int cost = 0; + int b; + MACROBLOCKD *x = &mb->e_mbd; + + + for (b = 0; b < 16; b++) + if (labels[ b] == which_label) + cost += cost_coeffs(mb, x->block + b, 3, + t->a + vp8_block2above[b], + t->l + vp8_block2left[b]); + + return cost; + +} +static unsigned int vp8_encode_inter_mb_segment(MACROBLOCK *x, int const *labels, int which_label, const vp8_encodemb_rtcd_vtable_t *rtcd) +{ + int i; + unsigned int distortion = 0; + + for (i = 0; i < 16; i++) + { + if (labels[i] == which_label) + { + BLOCKD *bd = &x->e_mbd.block[i]; + BLOCK *be = &x->block[i]; + + + vp8_build_inter_predictors_b(bd, 16, x->e_mbd.subpixel_predict); + ENCODEMB_INVOKE(rtcd, subb)(be, bd, 16); + x->short_fdct4x4rd(be->src_diff, be->coeff, 32); + + // set to 0 no way to account for 2nd order DC so discount + //be->coeff[0] = 0; + x->quantize_brd(be, bd); + + distortion += ENCODEMB_INVOKE(rtcd, berr)(be->coeff, bd->dqcoeff); + } + } + + return distortion; +} + +static void macro_block_yrd(MACROBLOCK *mb, int *Rate, int *Distortion, const vp8_encodemb_rtcd_vtable_t *rtcd) +{ + int b; + MACROBLOCKD *const x = &mb->e_mbd; + BLOCK *const mb_y2 = mb->block + 24; + BLOCKD *const x_y2 = x->block + 24; + short *Y2DCPtr = mb_y2->src_diff; + BLOCK *beptr; + int d; + + ENCODEMB_INVOKE(rtcd, submby)(mb->src_diff, mb->src.y_buffer, mb->e_mbd.predictor, mb->src.y_stride); + + // Fdct and building the 2nd order block + for (beptr = mb->block; beptr < mb->block + 16; beptr += 2) + { + mb->short_fdct8x4rd(beptr->src_diff, beptr->coeff, 32); + *Y2DCPtr++ = beptr->coeff[0]; + *Y2DCPtr++ = beptr->coeff[16]; + } + + // 2nd order fdct + if (x->mbmi.mode != SPLITMV) + { + mb->short_walsh4x4(mb_y2->src_diff, mb_y2->coeff, 8); + } + + // Quantization + for (b = 0; b < 16; b++) + { + mb->quantize_brd(&mb->block[b], &mb->e_mbd.block[b]); + } + + // DC predication and Quantization of 2nd Order block + if (x->mbmi.mode != SPLITMV) + { + + { + mb->quantize_brd(mb_y2, x_y2); + } + } + + // Distortion + if (x->mbmi.mode == SPLITMV) + d = ENCODEMB_INVOKE(rtcd, mberr)(mb, 0) << 2; + else + { + d = ENCODEMB_INVOKE(rtcd, mberr)(mb, 1) << 2; + d += ENCODEMB_INVOKE(rtcd, berr)(mb_y2->coeff, x_y2->dqcoeff); + } + + *Distortion = (d >> 4); + + // rate + *Rate = vp8_rdcost_mby(mb); +} + +static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, MV *best_ref_mv, int best_rd, int *mdcounts, int *returntotrate, int *returnyrate, int *returndistortion, int compressor_speed, int *mvcost[2], int mvthresh, int fullpixel) +{ + int i, segmentation; + B_PREDICTION_MODE this_mode; + MACROBLOCKD *xc = &x->e_mbd; + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + BLOCK *c = &x->block[0]; + BLOCKD *e = &x->e_mbd.block[0]; + int const *labels; + int best_segment_rd = INT_MAX; + int best_seg = 0; + int br = 0; + int bd = 0; + int bsr = 0; + int bsd = 0; + int bestsegmentyrate = 0; + + // FIX TO Rd error outrange bug PGW 9 june 2004 + B_PREDICTION_MODE bmodes[16] = {ZERO4X4, ZERO4X4, ZERO4X4, ZERO4X4, + ZERO4X4, ZERO4X4, ZERO4X4, ZERO4X4, + ZERO4X4, ZERO4X4, ZERO4X4, ZERO4X4, + ZERO4X4, ZERO4X4, ZERO4X4, ZERO4X4 + }; + + MV bmvs[16]; + int beobs[16]; + + for (segmentation = 0; segmentation < VP8_NUMMBSPLITS; segmentation++) + { + int label_count; + int this_segment_rd = 0; + int label_mv_thresh; + int rate = 0; + int sbr = 0; + int sbd = 0; + int UNINITIALIZED_IS_SAFE(sseshift); + int segmentyrate = 0; + + vp8_variance_fn_ptr_t v_fn_ptr; + + TEMP_CONTEXT t; + TEMP_CONTEXT tb; + vp8_setup_temp_context(&t, xc->above_context[Y1CONTEXT], xc->left_context[Y1CONTEXT], 4); + + br = 0; + bd = 0; + + switch (segmentation) + { + case 0: + v_fn_ptr.vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x8); + v_fn_ptr.svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar16x8); + v_fn_ptr.sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x8); + v_fn_ptr.sdx3f = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x8x3); + v_fn_ptr.sdx4df = VARIANCE_INVOKE(&cpi->rtcd.variance, sad16x8x4d); + sseshift = 3; + break; + case 1: + v_fn_ptr.vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var8x16); + v_fn_ptr.svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar8x16); + v_fn_ptr.sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x16); + v_fn_ptr.sdx3f = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x16x3); + v_fn_ptr.sdx4df = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x16x4d); + sseshift = 3; + break; + case 2: + v_fn_ptr.vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var8x8); + v_fn_ptr.svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar8x8); + v_fn_ptr.sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x8); + v_fn_ptr.sdx3f = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x8x3); + v_fn_ptr.sdx4df = VARIANCE_INVOKE(&cpi->rtcd.variance, sad8x8x4d); + sseshift = 2; + break; + case 3: + v_fn_ptr.vf = VARIANCE_INVOKE(&cpi->rtcd.variance, var4x4); + v_fn_ptr.svf = VARIANCE_INVOKE(&cpi->rtcd.variance, subpixvar4x4); + v_fn_ptr.sdf = VARIANCE_INVOKE(&cpi->rtcd.variance, sad4x4); + v_fn_ptr.sdx3f = VARIANCE_INVOKE(&cpi->rtcd.variance, sad4x4x3); + v_fn_ptr.sdx4df = VARIANCE_INVOKE(&cpi->rtcd.variance, sad4x4x4d); + sseshift = 0; + break; + } + + labels = vp8_mbsplits[segmentation]; + label_count = vp8_count_labels(labels); + + // 64 makes this threshold really big effectively + // making it so that we very rarely check mvs on + // segments. setting this to 1 would make mv thresh + // roughly equal to what it is for macroblocks + label_mv_thresh = 1 * mvthresh / label_count ; + + // Segmentation method overheads + rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation); + + rate += vp8_cost_mv_ref(SPLITMV, mdcounts); + + this_segment_rd += RDFUNC(x->rdmult, x->rddiv, rate, 0, cpi->target_bits_per_mb); + br += rate; + + for (i = 0; i < label_count; i++) + { + MV mode_mv[B_MODE_COUNT]; + int best_label_rd = INT_MAX; + B_PREDICTION_MODE mode_selected = ZERO4X4; + int j; + int bestlabelyrate = 0; + + b = &x->block[0]; + d = &x->e_mbd.block[0]; + + + // find first label + for (j = 0; j < 16; j++) + if (labels[j] == i) + break; + + c = &x->block[j]; + e = &x->e_mbd.block[j]; + + // search for the best motion vector on this segment + for (this_mode = LEFT4X4; this_mode <= NEW4X4 ; this_mode ++) + { + int distortion; + int this_rd; + int num00; + int labelyrate; + + TEMP_CONTEXT ts; + vp8_setup_temp_context(&ts, &t.a[0], &t.l[0], 4); + + if (this_mode == NEW4X4) + { + int step_param = 0; + int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; + int n; + int thissme; + int bestsme = INT_MAX; + MV temp_mv; + + // Is the best so far sufficiently good that we cant justify doing and new motion search. + if (best_label_rd < label_mv_thresh) + break; + + { + int sadpb = x->sadperbit4; + + if (cpi->sf.search_method == HEX) + bestsme = vp8_hex_search(x, c, e, best_ref_mv, &mode_mv[NEW4X4], step_param, sadpb/*x->errorperbit*/, &num00, v_fn_ptr.vf, v_fn_ptr.sdf, x->mvsadcost, mvcost); + else + { + bestsme = cpi->diamond_search_sad(x, c, e, best_ref_mv, &mode_mv[NEW4X4], step_param, sadpb / 2/*x->errorperbit*/, &num00, &v_fn_ptr, x->mvsadcost, mvcost); + + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = cpi->diamond_search_sad(x, c, e, best_ref_mv, &temp_mv, step_param + n, sadpb / 2/*x->errorperbit*/, &num00, &v_fn_ptr, x->mvsadcost, mvcost); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEW4X4].row = temp_mv.row; + mode_mv[NEW4X4].col = temp_mv.col; + } + } + } + } + + // Should we do a full search (best quality only) + if ((compressor_speed == 0) && (bestsme >> sseshift) > 4000) + { + thissme = cpi->full_search_sad(x, c, e, best_ref_mv, sadpb / 4, 16, &v_fn_ptr, x->mvcost, x->mvsadcost); + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEW4X4] = e->bmi.mv.as_mv; + } + else + { + // The full search result is actually worse so re-instate the previous best vector + e->bmi.mv.as_mv = mode_mv[NEW4X4]; + } + } + } + + if (bestsme < INT_MAX) + { + if (!fullpixel) + cpi->find_fractional_mv_step(x, c, e, &mode_mv[NEW4X4], best_ref_mv, x->errorperbit / 2, v_fn_ptr.svf, v_fn_ptr.vf, mvcost); + else + vp8_skip_fractional_mv_step(x, c, e, &mode_mv[NEW4X4], best_ref_mv, x->errorperbit, v_fn_ptr.svf, v_fn_ptr.vf, mvcost); + } + } + + rate = labels2mode(x, labels, i, this_mode, &mode_mv[this_mode], best_ref_mv, mvcost); + + // Trap vectors that reach beyond the UMV borders + if (((mode_mv[this_mode].row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].col >> 3) > x->mv_col_max)) + { + continue; + } + + distortion = vp8_encode_inter_mb_segment(x, labels, i, IF_RTCD(&cpi->rtcd.encodemb)) / 4; + + labelyrate = rdcost_mbsegment_y(x, labels, i, &ts); + rate += labelyrate; + + this_rd = RDFUNC(x->rdmult, x->rddiv, rate, distortion, cpi->target_bits_per_mb); + + if (this_rd < best_label_rd) + { + sbr = rate; + sbd = distortion; + bestlabelyrate = labelyrate; + mode_selected = this_mode; + best_label_rd = this_rd; + vp8_setup_temp_context(&tb, &ts.a[0], &ts.l[0], 4); + + } + } + + vp8_setup_temp_context(&t, &tb.a[0], &tb.l[0], 4); + + labels2mode(x, labels, i, mode_selected, &mode_mv[mode_selected], best_ref_mv, mvcost); + + br += sbr; + bd += sbd; + segmentyrate += bestlabelyrate; + this_segment_rd += best_label_rd; + + if ((this_segment_rd > best_rd) || (this_segment_rd > best_segment_rd)) + break; + } + + if ((this_segment_rd <= best_rd) && (this_segment_rd < best_segment_rd)) + { + bsr = br; + bsd = bd; + bestsegmentyrate = segmentyrate; + best_segment_rd = this_segment_rd; + best_seg = segmentation; + + // store everything needed to come back to this!! + for (i = 0; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + + bmvs[i] = bd->bmi.mv.as_mv; + bmodes[i] = bd->bmi.mode; + beobs[i] = bd->eob; + } + } + } + + // set it to the best + for (i = 0; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + + bd->bmi.mv.as_mv = bmvs[i]; + bd->bmi.mode = bmodes[i]; + bd->eob = beobs[i]; + } + + // Trap cases where the best split mode has all vectors coded 0,0 (or all the same) + if (FALSE) + { + int allsame = 1; + + for (i = 1; i < 16; i++) + { + if ((bmvs[i].col != bmvs[i-1].col) || (bmvs[i].row != bmvs[i-1].row)) + { + allsame = 0; + break; + } + } + + if (allsame) + { + best_segment_rd = INT_MAX; + } + } + + *returntotrate = bsr; + *returndistortion = bsd; + *returnyrate = bestsegmentyrate; + + + + // save partitions + labels = vp8_mbsplits[best_seg]; + x->e_mbd.mbmi.partitioning = best_seg; + x->e_mbd.mbmi.partition_count = vp8_count_labels(labels); + + for (i = 0; i < x->e_mbd.mbmi.partition_count; i++) + { + int j; + + for (j = 0; j < 16; j++) + { + if (labels[j] == i) + break; + } + + x->e_mbd.mbmi.partition_bmi[i].mode = x->e_mbd.block[j].bmi.mode; + x->e_mbd.mbmi.partition_bmi[i].mv.as_mv = x->e_mbd.block[j].bmi.mv.as_mv; + } + + return best_segment_rd; +} + + +int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra) +{ + BLOCK *b = &x->block[0]; + BLOCKD *d = &x->e_mbd.block[0]; + MACROBLOCKD *xd = &x->e_mbd; + B_MODE_INFO best_bmodes[16]; + MB_MODE_INFO best_mbmode; + MV best_ref_mv; + MV mode_mv[MB_MODE_COUNT]; + MB_PREDICTION_MODE this_mode; + int num00; + int best_mode_index = 0; + + int i; + int mode_index; + int mdcounts[4]; + int rate; + int distortion; + int best_rd = INT_MAX; // 1 << 30; + int ref_frame_cost[MAX_REF_FRAMES]; + int rate2, distortion2; + int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; + int rate_y, UNINITIALIZED_IS_SAFE(rate_uv); + + //int all_rds[MAX_MODES]; // Experimental debug code. + //int all_rates[MAX_MODES]; + //int all_dist[MAX_MODES]; + //int intermodecost[MAX_MODES]; + + MB_PREDICTION_MODE uv_intra_mode; + int sse; + int sum; + int uvintra_eob = 0; + int tteob = 0; + int force_no_skip = 0; + + *returnintra = INT_MAX; + + cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame + + x->skip = 0; + + ref_frame_cost[INTRA_FRAME] = vp8_cost_zero(cpi->prob_intra_coded); + + // Experimental code + // Adjust the RD multiplier based on the best case distortion we saw in the most recently coded mb + //if ( (cpi->last_mb_distortion) > 0 && (cpi->target_bits_per_mb > 0) ) + /*{ + int tmprdmult; + + //tmprdmult = (cpi->last_mb_distortion * 256) / ((cpi->av_per_frame_bandwidth*256)/cpi->common.MBs); + tmprdmult = (cpi->last_mb_distortion * 256) / cpi->target_bits_per_mb; + //tmprdmult = tmprdmult; + + //if ( tmprdmult > cpi->RDMULT * 2 ) + // tmprdmult = cpi->RDMULT * 2; + //else if ( tmprdmult < cpi->RDMULT / 2 ) + // tmprdmult = cpi->RDMULT / 2; + + //tmprdmult = (tmprdmult < 25) ? 25 : tmprdmult; + + //x->rdmult = tmprdmult; + + }*/ + + // Special case treatment when GF and ARF are not sensible options for reference + if (cpi->ref_frame_flags == VP8_LAST_FLAG) + { + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_zero(255); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(255) + + vp8_cost_zero(128); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(255) + + vp8_cost_one(128); + } + else + { + ref_frame_cost[LAST_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_zero(cpi->prob_last_coded); + ref_frame_cost[GOLDEN_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_zero(cpi->prob_gf_coded); + ref_frame_cost[ALTREF_FRAME] = vp8_cost_one(cpi->prob_intra_coded) + + vp8_cost_one(cpi->prob_last_coded) + + vp8_cost_one(cpi->prob_gf_coded); + } + + vpx_memset(mode_mv, 0, sizeof(mode_mv)); + + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + vp8_rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion); + uv_intra_mode = x->e_mbd.mbmi.uv_mode; + { + uvintra_eob = 0; + + for (i = 16; i < 24; i++) + uvintra_eob += x->e_mbd.block[i].eob; + } + + for (mode_index = 0; mode_index < MAX_MODES; mode_index++) + { + int frame_cost; + int this_rd = INT_MAX; + int lf_or_gf = 0; // Lat Frame (01) or gf/arf (1) + int disable_skip = 0; + + force_no_skip = 0; + + // Experimental debug code. + // Record of rd values recorded for this MB. -1 indicates not measured + //all_rds[mode_index] = -1; + //all_rates[mode_index] = -1; + //all_dist[mode_index] = -1; + //intermodecost[mode_index] = -1; + + // Test best rd so far against threshold for trying this mode. + if (best_rd <= cpi->rd_threshes[mode_index]) + continue; + + + + // These variables hold are rolling total cost and distortion for this mode + rate2 = 0; + distortion2 = 0; + + // Where skip is allowable add in the default per mb cost for the no skip case. + // where we then decide to skip we have to delete this and replace it with the + // cost of signallying a skip + if (cpi->common.mb_no_coeff_skip) + { + rate2 += vp8_cost_bit(cpi->prob_skip_false, 0); + } + + this_mode = vp8_mode_order[mode_index]; + + x->e_mbd.mbmi.mode = this_mode; + x->e_mbd.mbmi.uv_mode = DC_PRED; + x->e_mbd.mbmi.ref_frame = vp8_ref_frame_order[mode_index]; + + //Only consider ZEROMV/ALTREF_FRAME for alt ref frame. + if (cpi->is_src_frame_alt_ref) + { + if (this_mode != ZEROMV || x->e_mbd.mbmi.ref_frame != ALTREF_FRAME) + continue; + } + + if (x->e_mbd.mbmi.ref_frame == LAST_FRAME) + { + if (!(cpi->ref_frame_flags & VP8_LAST_FLAG)) + continue; + + lf_or_gf = 0; // Local last frame vs Golden frame flag + + // Set up pointers for this macro block into the previous frame recon buffer + x->e_mbd.pre.y_buffer = cpi->common.last_frame.y_buffer + recon_yoffset; + x->e_mbd.pre.u_buffer = cpi->common.last_frame.u_buffer + recon_uvoffset; + x->e_mbd.pre.v_buffer = cpi->common.last_frame.v_buffer + recon_uvoffset; + } + else if (x->e_mbd.mbmi.ref_frame == GOLDEN_FRAME) + { + + // not supposed to reference gold frame + if (!(cpi->ref_frame_flags & VP8_GOLD_FLAG)) + continue; + + lf_or_gf = 1; // Local last frame vs Golden frame flag + + // Set up pointers for this macro block into the previous frame recon buffer + x->e_mbd.pre.y_buffer = cpi->common.golden_frame.y_buffer + recon_yoffset; + x->e_mbd.pre.u_buffer = cpi->common.golden_frame.u_buffer + recon_uvoffset; + x->e_mbd.pre.v_buffer = cpi->common.golden_frame.v_buffer + recon_uvoffset; + } + else if (x->e_mbd.mbmi.ref_frame == ALTREF_FRAME) + { + // not supposed to reference alt ref frame + if (!(cpi->ref_frame_flags & VP8_ALT_FLAG)) + continue; + + //if ( !cpi->source_alt_ref_active ) + // continue; + + lf_or_gf = 1; // Local last frame vs Golden frame flag + + // Set up pointers for this macro block into the previous frame recon buffer + x->e_mbd.pre.y_buffer = cpi->common.alt_ref_frame.y_buffer + recon_yoffset; + x->e_mbd.pre.u_buffer = cpi->common.alt_ref_frame.u_buffer + recon_uvoffset; + x->e_mbd.pre.v_buffer = cpi->common.alt_ref_frame.v_buffer + recon_uvoffset; + } + + vp8_find_near_mvs(&x->e_mbd, + x->e_mbd.mode_info_context, + &mode_mv[NEARESTMV], &mode_mv[NEARMV], &best_ref_mv, + mdcounts, x->e_mbd.mbmi.ref_frame, cpi->common.ref_frame_sign_bias); + + + // Estimate the reference frame signaling cost and add it to the rolling cost variable. + frame_cost = ref_frame_cost[x->e_mbd.mbmi.ref_frame]; + rate2 += frame_cost; + + if (this_mode <= B_PRED) + { + for (i = 0; i < 16; i++) + { + vpx_memset(&x->e_mbd.block[i].bmi, 0, sizeof(B_MODE_INFO)); + } + } + + // Check to see if the testing frequency for this mode is at its max + // If so then prevent it from being tested and increase the threshold for its testing + if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) + { + if (cpi->mbs_tested_so_far <= cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index]) + { + // Increase the threshold for coding this mode to make it less likely to be chosen + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + + continue; + } + } + + // We have now reached the point where we are going to test the current mode so increment the counter for the number of times it has been tested + cpi->mode_test_hit_counts[mode_index] ++; + + // Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise + if (cpi->zbin_mode_boost_enabled) + { + if ((vp8_mode_order[mode_index] == ZEROMV) && (vp8_ref_frame_order[mode_index] != LAST_FRAME)) + cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST; + else + cpi->zbin_mode_boost = 0; + + vp8cx_mb_init_quantizer(cpi, x); + } + + switch (this_mode) + { + case B_PRED: + + // Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED]; + vp8_rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion); + rate2 += rate; + //rate_y = rate; + distortion2 += distortion; + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + break; + + case SPLITMV: + { + int frame_cost_rd = RDFUNC(x->rdmult, x->rddiv, frame_cost, 0, cpi->target_bits_per_mb); + int saved_rate = rate2; + + // vp8_rd_pick_best_mbsegmentation looks only at Y and does not account for frame_cost. + // (best_rd - frame_cost_rd) is thus a conservative breakout number. + int breakout_rd = best_rd - frame_cost_rd; + int tmp_rd; + + if (x->e_mbd.mbmi.ref_frame == LAST_FRAME) + tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, breakout_rd, mdcounts, &rate, &rate_y, &distortion, cpi->compressor_speed, x->mvcost, cpi->rd_threshes[THR_NEWMV], cpi->common.full_pixel) ; + else if (x->e_mbd.mbmi.ref_frame == GOLDEN_FRAME) + tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, breakout_rd, mdcounts, &rate, &rate_y, &distortion, cpi->compressor_speed, x->mvcost, cpi->rd_threshes[THR_NEWG], cpi->common.full_pixel) ; + else + tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, breakout_rd, mdcounts, &rate, &rate_y, &distortion, cpi->compressor_speed, x->mvcost, cpi->rd_threshes[THR_NEWA], cpi->common.full_pixel) ; + + rate2 += rate; + distortion2 += distortion; + + // If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV + if (tmp_rd < breakout_rd) + { + // Now work out UV cost and add it in + vp8_rd_inter_uv(cpi, x, &rate, &distortion, cpi->common.full_pixel); + rate2 += rate; + rate_uv = rate; + distortion2 += distortion; + + } + else + { + this_rd = INT_MAX; + disable_skip = 1; + } + + // Trap cases where the best split mode has all vectors coded 0,0 (or all the same) + if (0) + { + int allsame = 1; + + for (i = 1; i < 16; i++) + { + BLOCKD *bd = &x->e_mbd.block[i]; + + if (bd->bmi.mv.as_int != x->e_mbd.block[0].bmi.mv.as_int) //(bmvs[i].col != bmvs[i-1].col) || (bmvs[i].row != bmvs[i-1].row ) ) + { + allsame = 0; + break; + } + } + + if (allsame) + { + // reset mode and mv and jump to newmv + this_mode = NEWMV; + distortion2 = 0; + rate2 = saved_rate; + mode_mv[NEWMV].row = x->e_mbd.block[0].bmi.mv.as_mv.row; + mode_mv[NEWMV].col = x->e_mbd.block[0].bmi.mv.as_mv.col; + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); + goto mv_selected; + } + } + + // trap cases where the 8x8s can be promoted to 8x16s or 16x8s + if (0)//x->e_mbd.mbmi.partition_count == 4) + { + + if (x->e_mbd.mbmi.partition_bmi[0].mv.as_int == x->e_mbd.mbmi.partition_bmi[1].mv.as_int + && x->e_mbd.mbmi.partition_bmi[2].mv.as_int == x->e_mbd.mbmi.partition_bmi[3].mv.as_int) + { + const int *labels = vp8_mbsplits[2]; + x->e_mbd.mbmi.partitioning = 0; + rate -= vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + 2); + rate += vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings); + //rate -= x->inter_bmode_costs[ x->e_mbd.mbmi.partition_bmi[1]]; + //rate -= x->inter_bmode_costs[ x->e_mbd.mbmi.partition_bmi[3]]; + x->e_mbd.mbmi.partition_bmi[1] = x->e_mbd.mbmi.partition_bmi[2]; + } + } + + } + break; + case DC_PRED: + case V_PRED: + case H_PRED: + case TM_PRED: + x->e_mbd.mbmi.ref_frame = INTRA_FRAME; + vp8_build_intra_predictors_mby_ptr(&x->e_mbd); + { + macro_block_yrd(x, &rate, &distortion, IF_RTCD(&cpi->rtcd.encodemb)) ; + rate2 += rate; + rate_y = rate; + distortion2 += distortion; + rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mbmi.mode]; + rate2 += uv_intra_rate; + rate_uv = uv_intra_rate_tokenonly; + distortion2 += uv_intra_distortion; + } + break; + + case NEWMV: + + // Decrement full search counter + if (cpi->check_freq[lf_or_gf] > 0) + cpi->check_freq[lf_or_gf] --; + + { + int thissme; + int bestsme = INT_MAX; + int step_param = cpi->sf.first_step; + int search_range; + int further_steps; + int n; + + // Work out how long a search we should do + search_range = MAXF(abs(best_ref_mv.col), abs(best_ref_mv.row)) >> 3; + + if (search_range >= x->vector_range) + x->vector_range = search_range; + else if (x->vector_range > cpi->sf.min_fs_radius) + x->vector_range--; + + // Initial step/diamond search + { + int sadpb = x->sadperbit16; + + if (cpi->sf.search_method == HEX) + { + bestsme = vp8_hex_search(x, b, d, &best_ref_mv, &d->bmi.mv.as_mv, step_param, sadpb/*x->errorperbit*/, &num00, cpi->fn_ptr.vf, cpi->fn_ptr.sdf, x->mvsadcost, x->mvcost); + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + } + else + { + bestsme = cpi->diamond_search_sad(x, b, d, &best_ref_mv, &d->bmi.mv.as_mv, step_param, sadpb / 2/*x->errorperbit*/, &num00, &cpi->fn_ptr, x->mvsadcost, x->mvcost); //sadpb < 9 + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + + // Further step/diamond searches as necessary + n = 0; + further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; + + n = num00; + num00 = 0; + + while (n < further_steps) + { + n++; + + if (num00) + num00--; + else + { + thissme = cpi->diamond_search_sad(x, b, d, &best_ref_mv, &d->bmi.mv.as_mv, step_param + n, sadpb / 4/*x->errorperbit*/, &num00, &cpi->fn_ptr, x->mvsadcost, x->mvcost); //sadpb = 9 + + if (thissme < bestsme) + { + bestsme = thissme; + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + } + else + { + d->bmi.mv.as_mv.row = mode_mv[NEWMV].row; + d->bmi.mv.as_mv.col = mode_mv[NEWMV].col; + } + } + } + } + + } + + // Should we do a full search + if (!cpi->check_freq[lf_or_gf] || cpi->do_full[lf_or_gf]) + { + int thissme; + int full_flag_thresh = 0; + + // Update x->vector_range based on best vector found in step search + search_range = MAXF(abs(d->bmi.mv.as_mv.row), abs(d->bmi.mv.as_mv.col)); + + if (search_range > x->vector_range) + x->vector_range = search_range; + else + search_range = x->vector_range; + + // Apply limits + search_range = (search_range > cpi->sf.max_fs_radius) ? cpi->sf.max_fs_radius : search_range; + { + int sadpb = x->sadperbit16 >> 2; + thissme = cpi->full_search_sad(x, b, d, &best_ref_mv, sadpb, search_range, &cpi->fn_ptr, x->mvcost, x->mvsadcost); + } + + // Barrier threshold to initiating full search + // full_flag_thresh = 10 + (thissme >> 7); + if ((thissme + full_flag_thresh) < bestsme) + { + cpi->do_full[lf_or_gf] ++; + bestsme = thissme; + } + else if (thissme < bestsme) + bestsme = thissme; + else + { + cpi->do_full[lf_or_gf] = cpi->do_full[lf_or_gf] >> 1; + cpi->check_freq[lf_or_gf] = cpi->sf.full_freq[lf_or_gf]; + + // The full search result is actually worse so re-instate the previous best vector + d->bmi.mv.as_mv.row = mode_mv[NEWMV].row; + d->bmi.mv.as_mv.col = mode_mv[NEWMV].col; + } + } + + if (bestsme < INT_MAX) + // cpi->find_fractional_mv_step(x,b,d,&d->bmi.mv.as_mv,&best_ref_mv,x->errorperbit/2,cpi->fn_ptr.svf,cpi->fn_ptr.vf,x->mvcost); // normal mvc=11 + cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv.as_mv, &best_ref_mv, x->errorperbit / 4, cpi->fn_ptr.svf, cpi->fn_ptr.vf, x->mvcost); + + mode_mv[NEWMV].row = d->bmi.mv.as_mv.row; + mode_mv[NEWMV].col = d->bmi.mv.as_mv.col; + + // Add the new motion vector cost to our rolling cost variable + rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); + + } + + case NEARESTMV: + case NEARMV: + + // Clip "next_nearest" so that it does not extend to far out of image + if (mode_mv[this_mode].col < (xd->mb_to_left_edge - LEFT_TOP_MARGIN)) + mode_mv[this_mode].col = xd->mb_to_left_edge - LEFT_TOP_MARGIN; + else if (mode_mv[this_mode].col > xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN) + mode_mv[this_mode].col = xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN; + + if (mode_mv[this_mode].row < (xd->mb_to_top_edge - LEFT_TOP_MARGIN)) + mode_mv[this_mode].row = xd->mb_to_top_edge - LEFT_TOP_MARGIN; + else if (mode_mv[this_mode].row > xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN) + mode_mv[this_mode].row = xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN; + + // Do not bother proceeding if the vector (from newmv,nearest or near) is 0,0 as this should then be coded using the zeromv mode. + if (((this_mode == NEARMV) || (this_mode == NEARESTMV)) && + ((mode_mv[this_mode].row == 0) && (mode_mv[this_mode].col == 0))) + continue; + + case ZEROMV: + + mv_selected: + + // Trap vectors that reach beyond the UMV borders + // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point + // because of the lack of break statements in the previous two cases. + if (((mode_mv[this_mode].row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].row >> 3) > x->mv_row_max) || + ((mode_mv[this_mode].col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].col >> 3) > x->mv_col_max)) + continue; + + vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); + vp8_build_inter_predictors_mby(&x->e_mbd); + VARIANCE_INVOKE(&cpi->rtcd.variance, get16x16var)(x->src.y_buffer, x->src.y_stride, x->e_mbd.predictor, 16, (unsigned int *)(&sse), &sum); + + if (cpi->active_map_enabled && x->active_ptr[0] == 0) + { + x->skip = 1; + } + else if (sse < x->encode_breakout) + { + // Check u and v to make sure skip is ok + int sse2 = 0; + + sse2 = VP8_UVSSE(x, IF_RTCD(&cpi->rtcd.variance)); + + if (sse2 * 2 < x->encode_breakout) + { + x->skip = 1; + distortion2 = sse; + rate2 = 500; + + disable_skip = 1; // We have no real rate data so trying to adjust for rate_y and rate_uv below will cause problems. + this_rd = RDFUNC(x->rdmult, x->rddiv, rate2, distortion2, cpi->target_bits_per_mb); + + break; // (PGW) Move break here from below - for now at least + } + else + x->skip = 0; + } + + //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code + + // Add in the Mv/mode cost + rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + + // Y cost and distortion + macro_block_yrd(x, &rate, &distortion, IF_RTCD(&cpi->rtcd.encodemb)); + rate2 += rate; + rate_y = rate; + distortion2 += distortion; + + // UV cost and distortion + vp8_rd_inter_uv(cpi, x, &rate, &distortion, cpi->common.full_pixel); + rate2 += rate; + rate_uv = rate; + distortion2 += distortion; + break; + + default: + break; + } + + if (!disable_skip) + { + // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate + if (cpi->common.mb_no_coeff_skip) + { + tteob = 0; + + for (i = 0; i <= 24; i++) + { + tteob += x->e_mbd.block[i].eob; + } + + if (tteob == 0) + { +#if 1 + rate2 -= (rate_y + rate_uv); + + // Back out no skip flag costing and add in skip flag costing + if (cpi->prob_skip_false) + { + rate2 += vp8_cost_bit(cpi->prob_skip_false, 1); + rate2 -= vp8_cost_bit(cpi->prob_skip_false, 0); + } + +#else + int rateuseskip; + int ratenotuseskip; + + + + ratenotuseskip = rate_y + rate_uv + vp8_cost_bit(cpi->prob_skip_false, 0); + rateuseskip = vp8_cost_bit(cpi->prob_skip_false, 1); + + if (1) // rateuseskip<ratenotuseskip) + { + rate2 -= ratenotuseskip; + rate2 += rateuseskip; + force_no_skip = 0; + } + else + { + force_no_skip = 1; + } + +#endif + } + +#if 0 + else + { + int rateuseskip; + int ratenotuseskip; + int maxdistortion; + int minrate; + int skip_rd; + + // distortion when no coeff is encoded + maxdistortion = macro_block_max_error(x); + + ratenotuseskip = rate_y + rate_uv + vp8_cost_bit(cpi->prob_skip_false, 0); + rateuseskip = vp8_cost_bit(cpi->prob_skip_false, 1); + + minrate = rateuseskip - ratenotuseskip; + + skip_rd = RDFUNC(x->rdmult, x->rddiv, minrate, maxdistortion - distortion2, cpi->target_bits_per_mb); + + if (skip_rd + 50 < 0 && x->e_mbd.mbmi.ref_frame != INTRA_FRAME && rate_y + rate_uv < 4000) + { + force_no_skip = 1; + rate2 = rate2 + rateuseskip - ratenotuseskip; + distortion2 = maxdistortion; + } + else + { + force_no_skip = 0; + } + + } + +#endif + + } + + // Calculate the final RD estimate for this mode + this_rd = RDFUNC(x->rdmult, x->rddiv, rate2, distortion2, cpi->target_bits_per_mb); + } + + // Experimental debug code. + //all_rds[mode_index] = this_rd; + //all_rates[mode_index] = rate2; + //all_dist[mode_index] = distortion2; + + if ((x->e_mbd.mbmi.ref_frame == INTRA_FRAME) && (this_rd < *returnintra)) + { + *returnintra = this_rd ; + } + + // Did this mode help.. i.i is it the new best mode + if (this_rd < best_rd || x->skip) + { + // Note index of best mode so far + best_mode_index = mode_index; + x->e_mbd.mbmi.force_no_skip = force_no_skip; + + if (this_mode <= B_PRED) + { + x->e_mbd.mbmi.uv_mode = uv_intra_mode; + } + + *returnrate = rate2; + *returndistortion = distortion2; + best_rd = this_rd; + vpx_memcpy(&best_mbmode, &x->e_mbd.mbmi, sizeof(MB_MODE_INFO)); + + for (i = 0; i < 16; i++) + { + vpx_memcpy(&best_bmodes[i], &x->e_mbd.block[i].bmi, sizeof(B_MODE_INFO)); + } + + // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time + cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + // If the mode did not help improve the best error case then raise the threshold for testing that mode next time around. + else + { + cpi->rd_thresh_mult[mode_index] += 4; + + if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) + cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; + + cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; + } + + if (x->skip) + break; + } + + // Reduce the activation RD thresholds for the best choice mode + if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) + { + int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 2); + + cpi->rd_thresh_mult[best_mode_index] = (cpi->rd_thresh_mult[best_mode_index] >= (MIN_THRESHMULT + best_adjustment)) ? cpi->rd_thresh_mult[best_mode_index] - best_adjustment : MIN_THRESHMULT; + cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; + + // If we chose a split mode then reset the new MV thresholds as well + /*if ( vp8_mode_order[best_mode_index] == SPLITMV ) + { + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWMV] >> 4); + cpi->rd_thresh_mult[THR_NEWMV] = (cpi->rd_thresh_mult[THR_NEWMV] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWMV]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWMV] = (cpi->rd_baseline_thresh[THR_NEWMV] >> 7) * cpi->rd_thresh_mult[THR_NEWMV]; + + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWG] >> 4); + cpi->rd_thresh_mult[THR_NEWG] = (cpi->rd_thresh_mult[THR_NEWG] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWG]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWG] = (cpi->rd_baseline_thresh[THR_NEWG] >> 7) * cpi->rd_thresh_mult[THR_NEWG]; + + best_adjustment = 4; //(cpi->rd_thresh_mult[THR_NEWA] >> 4); + cpi->rd_thresh_mult[THR_NEWA] = (cpi->rd_thresh_mult[THR_NEWA] >= (MIN_THRESHMULT+best_adjustment)) ? cpi->rd_thresh_mult[THR_NEWA]-best_adjustment: MIN_THRESHMULT; + cpi->rd_threshes[THR_NEWA] = (cpi->rd_baseline_thresh[THR_NEWA] >> 7) * cpi->rd_thresh_mult[THR_NEWA]; + }*/ + + } + + // If we have chosen new mv or split then decay the full search check count more quickly. + if ((vp8_mode_order[best_mode_index] == NEWMV) || (vp8_mode_order[best_mode_index] == SPLITMV)) + { + int lf_or_gf = (vp8_ref_frame_order[best_mode_index] == LAST_FRAME) ? 0 : 1; + + if (cpi->check_freq[lf_or_gf] && !cpi->do_full[lf_or_gf]) + { + cpi->check_freq[lf_or_gf] --; + } + } + + // Keep a record of best mode index that we chose + cpi->last_best_mode_index = best_mode_index; + + // Note how often each mode chosen as best + cpi->mode_chosen_counts[best_mode_index] ++; + + + if (cpi->is_src_frame_alt_ref && (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) + { + best_mbmode.mode = ZEROMV; + best_mbmode.ref_frame = ALTREF_FRAME; + best_mbmode.mv.as_int = 0; + best_mbmode.uv_mode = 0; + best_mbmode.mb_skip_coeff = (cpi->common.mb_no_coeff_skip) ? 1 : 0; + best_mbmode.partitioning = 0; + best_mbmode.dc_diff = 0; + + vpx_memcpy(&x->e_mbd.mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + + for (i = 0; i < 16; i++) + { + vpx_memset(&x->e_mbd.block[i].bmi, 0, sizeof(B_MODE_INFO)); + } + + x->e_mbd.mbmi.mv.as_int = 0; + + return best_rd; + } + + + // macroblock modes + vpx_memcpy(&x->e_mbd.mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + + for (i = 0; i < 16; i++) + { + vpx_memcpy(&x->e_mbd.block[i].bmi, &best_bmodes[i], sizeof(B_MODE_INFO)); + } + + x->e_mbd.mbmi.mv.as_mv = x->e_mbd.block[15].bmi.mv.as_mv; + + return best_rd; +} +#endif +
diff --git a/vp8/encoder/rdopt.h b/vp8/encoder/rdopt.h new file mode 100644 index 0000000..c6eae4b --- /dev/null +++ b/vp8/encoder/rdopt.h
@@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_RDOPT_H +#define __INC_RDOPT_H +void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue); +int vp8_rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *rate, int *rate_to, int *distortion); +int vp8_rd_pick_intra16x16mby_mode(VP8_COMP *cpi, MACROBLOCK *x, int *returnrate, int *rate_to, int *returndistortion); +int vp8_rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int *rate_to, int *distortion); +extern int vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); + + +#endif
diff --git a/vp8/encoder/sad_c.c b/vp8/encoder/sad_c.c new file mode 100644 index 0000000..74c6bd7 --- /dev/null +++ b/vp8/encoder/sad_c.c
@@ -0,0 +1,248 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> + +unsigned int vp8_sad16x16_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + int r, c; + unsigned int sad = 0; + + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + sad += abs(src_ptr[c] - ref_ptr[c]); + } + + src_ptr += src_stride; + ref_ptr += ref_stride; + } + + return sad; +} + + +static __inline +unsigned int sad_mx_n_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int m, + int n) +{ + + int r, c; + unsigned int sad = 0; + + for (r = 0; r < n; r++) + { + for (c = 0; c < m; c++) + { + sad += abs(src_ptr[c] - ref_ptr[c]); + } + + src_ptr += src_stride; + ref_ptr += ref_stride; + } + + return sad; +} + + +unsigned int vp8_sad8x8_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, 8, 8); +} + + +unsigned int vp8_sad16x8_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, 16, 8); + +} + + +unsigned int vp8_sad8x16_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, 8, 16); +} + + +unsigned int vp8_sad4x4_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + int max_sad) +{ + + return sad_mx_n_c(src_ptr, src_stride, ref_ptr, ref_stride, 4, 4); +} + +void vp8_sad16x16x3_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad16x8x3_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad8x8x3_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad8x16x3_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad4x4x3_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr , ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 1, ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr + 2, ref_stride, 0x7fffffff); +} + +void vp8_sad16x16x4d_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad16x16_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad16x8x4d_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad16x8_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad8x8x4d_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad8x8_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad8x16x4d_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad8x16_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +} + +void vp8_sad4x4x4d_c( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr[], + int ref_stride, + unsigned int *sad_array +) +{ + sad_array[0] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[0], ref_stride, 0x7fffffff); + sad_array[1] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[1], ref_stride, 0x7fffffff); + sad_array[2] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[2], ref_stride, 0x7fffffff); + sad_array[3] = vp8_sad4x4_c(src_ptr, src_stride, ref_ptr[3], ref_stride, 0x7fffffff); +}
diff --git a/vp8/encoder/ssim.c b/vp8/encoder/ssim.c new file mode 100644 index 0000000..df214a8 --- /dev/null +++ b/vp8/encoder/ssim.c
@@ -0,0 +1,521 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_scale/yv12config.h" +#include "math.h" + +#define C1 (float)(64 * 64 * 0.01*255*0.01*255) +#define C2 (float)(64 * 64 * 0.03*255*0.03*255) + +static int width_y; +static int height_y; +static int height_uv; +static int width_uv; +static int stride_uv; +static int stride; +static int lumimask; +static int luminance; +static double plane_summed_weights = 0; + +static short img12_sum_block[8*4096*4096*2] ; + +static short img1_sum[8*4096*2]; +static short img2_sum[8*4096*2]; +static int img1_sq_sum[8*4096*2]; +static int img2_sq_sum[8*4096*2]; +static int img12_mul_sum[8*4096*2]; + + +double vp8_similarity +( + int mu_x, + int mu_y, + int pre_mu_x2, + int pre_mu_y2, + int pre_mu_xy2 +) +{ + int mu_x2, mu_y2, mu_xy, theta_x2, theta_y2, theta_xy; + + mu_x2 = mu_x * mu_x; + mu_y2 = mu_y * mu_y; + mu_xy = mu_x * mu_y; + + theta_x2 = 64 * pre_mu_x2 - mu_x2; + theta_y2 = 64 * pre_mu_y2 - mu_y2; + theta_xy = 64 * pre_mu_xy2 - mu_xy; + + return (2 * mu_xy + C1) * (2 * theta_xy + C2) / ((mu_x2 + mu_y2 + C1) * (theta_x2 + theta_y2 + C2)); +} + +double vp8_ssim +( + const unsigned char *img1, + const unsigned char *img2, + int stride_img1, + int stride_img2, + int width, + int height +) +{ + int x, y, x2, y2, img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block, temp; + + double plane_quality, weight, mean; + + short *img1_sum_ptr1, *img1_sum_ptr2; + short *img2_sum_ptr1, *img2_sum_ptr2; + int *img1_sq_sum_ptr1, *img1_sq_sum_ptr2; + int *img2_sq_sum_ptr1, *img2_sq_sum_ptr2; + int *img12_mul_sum_ptr1, *img12_mul_sum_ptr2; + + plane_quality = 0; + + if (lumimask) + plane_summed_weights = 0.0f; + else + plane_summed_weights = (height - 7) * (width - 7); + + //some prologue for the main loop + temp = 8 * width; + + img1_sum_ptr1 = img1_sum + temp; + img2_sum_ptr1 = img2_sum + temp; + img1_sq_sum_ptr1 = img1_sq_sum + temp; + img2_sq_sum_ptr1 = img2_sq_sum + temp; + img12_mul_sum_ptr1 = img12_mul_sum + temp; + + for (x = 0; x < width; x++) + { + img1_sum[x] = img1[x]; + img2_sum[x] = img2[x]; + img1_sq_sum[x] = img1[x] * img1[x]; + img2_sq_sum[x] = img2[x] * img2[x]; + img12_mul_sum[x] = img1[x] * img2[x]; + + img1_sum_ptr1[x] = 0; + img2_sum_ptr1[x] = 0; + img1_sq_sum_ptr1[x] = 0; + img2_sq_sum_ptr1[x] = 0; + img12_mul_sum_ptr1[x] = 0; + } + + //the main loop + for (y = 1; y < height; y++) + { + img1 += stride_img1; + img2 += stride_img2; + + temp = (y - 1) % 9 * width; + + img1_sum_ptr1 = img1_sum + temp; + img2_sum_ptr1 = img2_sum + temp; + img1_sq_sum_ptr1 = img1_sq_sum + temp; + img2_sq_sum_ptr1 = img2_sq_sum + temp; + img12_mul_sum_ptr1 = img12_mul_sum + temp; + + temp = y % 9 * width; + + img1_sum_ptr2 = img1_sum + temp; + img2_sum_ptr2 = img2_sum + temp; + img1_sq_sum_ptr2 = img1_sq_sum + temp; + img2_sq_sum_ptr2 = img2_sq_sum + temp; + img12_mul_sum_ptr2 = img12_mul_sum + temp; + + for (x = 0; x < width; x++) + { + img1_sum_ptr2[x] = img1_sum_ptr1[x] + img1[x]; + img2_sum_ptr2[x] = img2_sum_ptr1[x] + img2[x]; + img1_sq_sum_ptr2[x] = img1_sq_sum_ptr1[x] + img1[x] * img1[x]; + img2_sq_sum_ptr2[x] = img2_sq_sum_ptr1[x] + img2[x] * img2[x]; + img12_mul_sum_ptr2[x] = img12_mul_sum_ptr1[x] + img1[x] * img2[x]; + } + + if (y > 6) + { + //calculate the sum of the last 8 lines by subtracting the total sum of 8 lines back from the present sum + temp = (y + 1) % 9 * width; + + img1_sum_ptr1 = img1_sum + temp; + img2_sum_ptr1 = img2_sum + temp; + img1_sq_sum_ptr1 = img1_sq_sum + temp; + img2_sq_sum_ptr1 = img2_sq_sum + temp; + img12_mul_sum_ptr1 = img12_mul_sum + temp; + + for (x = 0; x < width; x++) + { + img1_sum_ptr1[x] = img1_sum_ptr2[x] - img1_sum_ptr1[x]; + img2_sum_ptr1[x] = img2_sum_ptr2[x] - img2_sum_ptr1[x]; + img1_sq_sum_ptr1[x] = img1_sq_sum_ptr2[x] - img1_sq_sum_ptr1[x]; + img2_sq_sum_ptr1[x] = img2_sq_sum_ptr2[x] - img2_sq_sum_ptr1[x]; + img12_mul_sum_ptr1[x] = img12_mul_sum_ptr2[x] - img12_mul_sum_ptr1[x]; + } + + //here we calculate the sum over the 8x8 block of pixels + //this is done by sliding a window across the column sums for the last 8 lines + //each time adding the new column sum, and subtracting the one which fell out of the window + img1_block = 0; + img2_block = 0; + img1_sq_block = 0; + img2_sq_block = 0; + img12_mul_block = 0; + + //prologue, and calculation of simularity measure from the first 8 column sums + for (x = 0; x < 8; x++) + { + img1_block += img1_sum_ptr1[x]; + img2_block += img2_sum_ptr1[x]; + img1_sq_block += img1_sq_sum_ptr1[x]; + img2_sq_block += img2_sq_sum_ptr1[x]; + img12_mul_block += img12_mul_sum_ptr1[x]; + } + + if (lumimask) + { + y2 = y - 7; + x2 = 0; + + if (luminance) + { + mean = (img2_block + img1_block) / 128.0f; + + if (!(y2 % 2 || x2 % 2)) + *(img12_sum_block + y2 / 2 * width_uv + x2 / 2) = img2_block + img1_block; + } + else + { + mean = *(img12_sum_block + y2 * width_uv + x2); + mean += *(img12_sum_block + y2 * width_uv + x2 + 4); + mean += *(img12_sum_block + (y2 + 4) * width_uv + x2); + mean += *(img12_sum_block + (y2 + 4) * width_uv + x2 + 4); + + mean /= 512.0f; + } + + weight = mean < 40 ? 0.0f : + (mean < 50 ? (mean - 40.0f) / 10.0f : 1.0f); + plane_summed_weights += weight; + + plane_quality += weight * vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); + } + else + plane_quality += vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); + + //and for the rest + for (x = 8; x < width; x++) + { + img1_block = img1_block + img1_sum_ptr1[x] - img1_sum_ptr1[x - 8]; + img2_block = img2_block + img2_sum_ptr1[x] - img2_sum_ptr1[x - 8]; + img1_sq_block = img1_sq_block + img1_sq_sum_ptr1[x] - img1_sq_sum_ptr1[x - 8]; + img2_sq_block = img2_sq_block + img2_sq_sum_ptr1[x] - img2_sq_sum_ptr1[x - 8]; + img12_mul_block = img12_mul_block + img12_mul_sum_ptr1[x] - img12_mul_sum_ptr1[x - 8]; + + if (lumimask) + { + y2 = y - 7; + x2 = x - 7; + + if (luminance) + { + mean = (img2_block + img1_block) / 128.0f; + + if (!(y2 % 2 || x2 % 2)) + *(img12_sum_block + y2 / 2 * width_uv + x2 / 2) = img2_block + img1_block; + } + else + { + mean = *(img12_sum_block + y2 * width_uv + x2); + mean += *(img12_sum_block + y2 * width_uv + x2 + 4); + mean += *(img12_sum_block + (y2 + 4) * width_uv + x2); + mean += *(img12_sum_block + (y2 + 4) * width_uv + x2 + 4); + + mean /= 512.0f; + } + + weight = mean < 40 ? 0.0f : + (mean < 50 ? (mean - 40.0f) / 10.0f : 1.0f); + plane_summed_weights += weight; + + plane_quality += weight * vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); + } + else + plane_quality += vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); + } + } + } + + if (plane_summed_weights == 0) + return 1.0f; + else + return plane_quality / plane_summed_weights; +} + +double vp8_calc_ssim +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + int lumamask, + double *weight +) +{ + double a, b, c; + double frame_weight; + double ssimv; + + width_y = source->y_width; + height_y = source->y_height; + height_uv = source->uv_height; + width_uv = source->uv_width; + stride_uv = dest->uv_stride; + stride = dest->y_stride; + + lumimask = lumamask; + + luminance = 1; + a = vp8_ssim(source->y_buffer, dest->y_buffer, + source->y_stride, dest->y_stride, source->y_width, source->y_height); + luminance = 0; + + frame_weight = plane_summed_weights / ((width_y - 7) * (height_y - 7)); + + if (frame_weight == 0) + a = b = c = 1.0f; + else + { + b = vp8_ssim(source->u_buffer, dest->u_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, source->uv_height); + + c = vp8_ssim(source->v_buffer, dest->v_buffer, + source->uv_stride, dest->uv_stride, source->uv_width, source->uv_height); + } + + ssimv = a * .8 + .1 * (b + c); + + *weight = frame_weight; + + return ssimv; +} + +// Google version of SSIM +// SSIM +#define KERNEL 3 +#define KERNEL_SIZE (2 * KERNEL + 1) + +typedef unsigned char uint8; +typedef unsigned int uint32; + +static const int K[KERNEL_SIZE] = +{ + 1, 4, 11, 16, 11, 4, 1 // 16 * exp(-0.3 * i * i) +}; +static const double ki_w = 1. / 2304.; // 1 / sum(i:0..6, j..6) K[i]*K[j] +double get_ssimg(const uint8 *org, const uint8 *rec, + int xo, int yo, int W, int H, + const int stride1, const int stride2 + ) +{ + // TODO(skal): use summed tables + int y, x; + + const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL; + const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL; + const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL; + const int xmax = (xo + KERNEL > W - 1) ? W - 1 : xo + KERNEL; + // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) + // with a diff of 255, squares. That would a max error of 0x8ee0900, + // which fits into 32 bits integers. + uint32 w = 0, xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; + org += ymin * stride1; + rec += ymin * stride2; + + for (y = ymin; y <= ymax; ++y, org += stride1, rec += stride2) + { + const int Wy = K[KERNEL + y - yo]; + + for (x = xmin; x <= xmax; ++x) + { + const int Wxy = Wy * K[KERNEL + x - xo]; + // TODO(skal): inlined assembly + w += Wxy; + xm += Wxy * org[x]; + ym += Wxy * rec[x]; + xxm += Wxy * org[x] * org[x]; + xym += Wxy * org[x] * rec[x]; + yym += Wxy * rec[x] * rec[x]; + } + } + + { + const double iw = 1. / w; + const double iwx = xm * iw; + const double iwy = ym * iw; + double sxx = xxm * iw - iwx * iwx; + double syy = yym * iw - iwy * iwy; + + // small errors are possible, due to rounding. Clamp to zero. + if (sxx < 0.) sxx = 0.; + + if (syy < 0.) syy = 0.; + + { + const double sxsy = sqrt(sxx * syy); + const double sxy = xym * iw - iwx * iwy; + static const double C11 = (0.01 * 0.01) * (255 * 255); + static const double C22 = (0.03 * 0.03) * (255 * 255); + static const double C33 = (0.015 * 0.015) * (255 * 255); + const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); + const double c = (2. * sxsy + C22) / (sxx + syy + C22); + + const double s = (sxy + C33) / (sxsy + C33); + return l * c * s; + + } + } + +} + +double get_ssimfull_kernelg(const uint8 *org, const uint8 *rec, + int xo, int yo, int W, int H, + const int stride1, const int stride2) +{ + // TODO(skal): use summed tables + // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) + // with a diff of 255, squares. That would a max error of 0x8ee0900, + // which fits into 32 bits integers. + int y_, x_; + uint32 xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; + org += (yo - KERNEL) * stride1; + org += (xo - KERNEL); + rec += (yo - KERNEL) * stride2; + rec += (xo - KERNEL); + + for (y_ = 0; y_ < KERNEL_SIZE; ++y_, org += stride1, rec += stride2) + { + const int Wy = K[y_]; + + for (x_ = 0; x_ < KERNEL_SIZE; ++x_) + { + const int Wxy = Wy * K[x_]; + // TODO(skal): inlined assembly + const int org_x = org[x_]; + const int rec_x = rec[x_]; + xm += Wxy * org_x; + ym += Wxy * rec_x; + xxm += Wxy * org_x * org_x; + xym += Wxy * org_x * rec_x; + yym += Wxy * rec_x * rec_x; + } + } + + { + const double iw = ki_w; + const double iwx = xm * iw; + const double iwy = ym * iw; + double sxx = xxm * iw - iwx * iwx; + double syy = yym * iw - iwy * iwy; + + // small errors are possible, due to rounding. Clamp to zero. + if (sxx < 0.) sxx = 0.; + + if (syy < 0.) syy = 0.; + + { + const double sxsy = sqrt(sxx * syy); + const double sxy = xym * iw - iwx * iwy; + static const double C11 = (0.01 * 0.01) * (255 * 255); + static const double C22 = (0.03 * 0.03) * (255 * 255); + static const double C33 = (0.015 * 0.015) * (255 * 255); + const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); + const double c = (2. * sxsy + C22) / (sxx + syy + C22); + const double s = (sxy + C33) / (sxsy + C33); + return l * c * s; + } + } +} + +double calc_ssimg(const uint8 *org, const uint8 *rec, + const int image_width, const int image_height, + const int stride1, const int stride2 + ) +{ + int j, i; + double SSIM = 0.; + + for (j = 0; j < KERNEL; ++j) + { + for (i = 0; i < image_width; ++i) + { + SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); + } + } + + for (j = KERNEL; j < image_height - KERNEL; ++j) + { + for (i = 0; i < KERNEL; ++i) + { + SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); + } + + for (i = KERNEL; i < image_width - KERNEL; ++i) + { + SSIM += get_ssimfull_kernelg(org, rec, i, j, + image_width, image_height, stride1, stride2); + } + + for (i = image_width - KERNEL; i < image_width; ++i) + { + SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); + } + } + + for (j = image_height - KERNEL; j < image_height; ++j) + { + for (i = 0; i < image_width; ++i) + { + SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); + } + } + + return SSIM; +} + + +double vp8_calc_ssimg +( + YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *dest, + double *ssim_y, + double *ssim_u, + double *ssim_v +) +{ + double ssim_all = 0; + int ysize = source->y_width * source->y_height; + int uvsize = ysize / 4; + + *ssim_y = calc_ssimg(source->y_buffer, dest->y_buffer, + source->y_width, source->y_height, + source->y_stride, dest->y_stride); + + + *ssim_u = calc_ssimg(source->u_buffer, dest->u_buffer, + source->uv_width, source->uv_height, + source->uv_stride, dest->uv_stride); + + + *ssim_v = calc_ssimg(source->v_buffer, dest->v_buffer, + source->uv_width, source->uv_height, + source->uv_stride, dest->uv_stride); + + ssim_all = (*ssim_y + *ssim_u + *ssim_v) / (ysize + uvsize + uvsize); + *ssim_y /= ysize; + *ssim_u /= uvsize; + *ssim_v /= uvsize; + return ssim_all; +}
diff --git a/vp8/encoder/tokenize.c b/vp8/encoder/tokenize.c new file mode 100644 index 0000000..33ddd64 --- /dev/null +++ b/vp8/encoder/tokenize.c
@@ -0,0 +1,636 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "onyx_int.h" +#include "tokenize.h" +#include "vpx_mem/vpx_mem.h" + +/* Global event counters used for accumulating statistics across several + compressions, then generating context.c = initial stats. */ + +#ifdef ENTROPY_STATS +_int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens]; +#endif +void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) ; +void vp8_fix_contexts(VP8_COMP *cpi, MACROBLOCKD *x); + +TOKENEXTRA vp8_dct_value_tokens[DCT_MAX_VALUE*2]; +TOKENEXTRA *vp8_dct_value_tokens_ptr; +int vp8_dct_value_cost[DCT_MAX_VALUE*2]; +int *vp8_dct_value_cost_ptr; +#if 0 +int skip_true_count = 0; +int skip_false_count = 0; +#endif +static void fill_value_tokens() +{ + + TOKENEXTRA *const t = vp8_dct_value_tokens + DCT_MAX_VALUE; + vp8_extra_bit_struct *const e = vp8_extra_bits; + + int i = -DCT_MAX_VALUE; + int sign = 1; + + do + { + if (!i) + sign = 0; + + { + const int a = sign ? -i : i; + int eb = sign; + + if (a > 4) + { + int j = 4; + + while (++j < 11 && e[j].base_val <= a) {} + + t[i].Token = --j; + eb |= (a - e[j].base_val) << 1; + } + else + t[i].Token = a; + + t[i].Extra = eb; + } + + // initialize the cost for extra bits for all possible coefficient value. + { + int cost = 0; + vp8_extra_bit_struct *p = vp8_extra_bits + t[i].Token; + + if (p->base_val) + { + const int extra = t[i].Extra; + const int Length = p->Len; + + if (Length) + cost += vp8_treed_cost(p->tree, p->prob, extra >> 1, Length); + + cost += vp8_cost_bit(vp8_prob_half, extra & 1); /* sign */ + vp8_dct_value_cost[i + DCT_MAX_VALUE] = cost; + } + + } + + } + while (++i < DCT_MAX_VALUE); + + vp8_dct_value_tokens_ptr = vp8_dct_value_tokens + DCT_MAX_VALUE; + vp8_dct_value_cost_ptr = vp8_dct_value_cost + DCT_MAX_VALUE; +} + +static void tokenize2nd_order_b +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int c = 0; /* start at DC */ + const int eob = b->eob; /* one beyond last nonzero coeff */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + int x; + const short *qcoeff_ptr = b->qcoeff; + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + do + { + const int band = vp8_coef_bands[c]; + + if (c < eob) + { + int rc = vp8_default_zig_zag1d[c]; + const int v = qcoeff_ptr[rc]; + + assert(-DCT_MAX_VALUE <= v && v < (DCT_MAX_VALUE)); + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + x = vp8_dct_value_tokens_ptr[v].Token; + } + else + x = DCT_EOB_TOKEN; + + t->Token = x; + t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; + + t->section = frametype * BLOCK_TYPES * 2 + 2 * type + (c == 0); + + t->skip_eob_node = pt == 0 && ((band > 0 && type > 0) || (band > 1 && type == 0)); + + ++cpi->coef_counts [type] [band] [pt] [x]; + } + while (pt = vp8_prev_token_class[x], ++t, c < eob && ++c < 16); + + *tp = t; + pt = (c != !type); /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} + +static void tokenize1st_order_b +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + int c = type ? 0 : 1; /* start at DC unless type 0 */ + const int eob = b->eob; /* one beyond last nonzero coeff */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + int x; + const short *qcoeff_ptr = b->qcoeff; + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + + do + { + const int band = vp8_coef_bands[c]; + + x = DCT_EOB_TOKEN; + + if (c < eob) + { + int rc = vp8_default_zig_zag1d[c]; + const int v = qcoeff_ptr[rc]; + + assert(-DCT_MAX_VALUE <= v && v < (DCT_MAX_VALUE)); + + t->Extra = vp8_dct_value_tokens_ptr[v].Extra; + x = vp8_dct_value_tokens_ptr[v].Token; + } + + t->Token = x; + t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; + + t->section = frametype * BLOCK_TYPES * 2 + 2 * type + (c == 0); + t->skip_eob_node = pt == 0 && ((band > 0 && type > 0) || (band > 1 && type == 0)); + + ++cpi->coef_counts [type] [band] [pt] [x]; + } + while (pt = vp8_prev_token_class[x], ++t, c < eob && ++c < 16); + + *tp = t; + pt = (c != !type); /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} +#if 0 +void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + //int i; + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + int plane_type; + int b; + + TOKENEXTRA *start = *t; + TOKENEXTRA *tp = *t; + + x->mbmi.dc_diff = 1; + + vpx_memcpy(cpi->coef_counts_backup, cpi->coef_counts, sizeof(cpi->coef_counts)); + + if (x->mbmi.mode == B_PRED || x->mbmi.mode == SPLITMV) + { + plane_type = 3; + } + else + { + tokenize2nd_order_b(x->block + 24, t, 1, x->frame_type, + A[Y2CONTEXT] + vp8_block2above[24], L[Y2CONTEXT] + vp8_block2left[24], cpi); + plane_type = 0; + + } + + for (b = 0; b < 16; b++) + tokenize1st_order_b(x->block + b, t, plane_type, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + + for (b = 16; b < 24; b++) + tokenize1st_order_b(x->block + b, t, 2, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + + if (cpi->common.mb_no_coeff_skip) + { + x->mbmi.mb_skip_coeff = 1; + + while ((tp != *t) && x->mbmi.mb_skip_coeff) + { + x->mbmi.mb_skip_coeff = (x->mbmi.mb_skip_coeff && (tp->Token == DCT_EOB_TOKEN)); + tp ++; + } + + if (x->mbmi.mb_skip_coeff == 1) + { + x->mbmi.dc_diff = 0; + //redo the coutnts + vpx_memcpy(cpi->coef_counts, cpi->coef_counts_backup, sizeof(cpi->coef_counts)); + + *t = start; + cpi->skip_true_count++; + + //skip_true_count++; + } + else + { + + cpi->skip_false_count++; + //skip_false_count++; + } + } +} +#else +void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + //int i; + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + int plane_type; + int b; + + TOKENEXTRA *start = *t; + TOKENEXTRA *tp = *t; + + x->mbmi.dc_diff = 1; + +#if 0 + + if (x->mbmi.force_no_skip) + { + x->mbmi.mb_skip_coeff = 1; + //reset for next_mb. + x->mbmi.force_no_skip = 0; + } + +#endif + +#if 1 + + if (x->mbmi.mb_skip_coeff) + { + + cpi->skip_true_count++; + + if (!cpi->common.mb_no_coeff_skip) + vp8_stuff_mb(cpi, x, t) ; + else + { + vp8_fix_contexts(cpi, x); + } + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + x->mbmi.dc_diff = 0; + else + x->mbmi.dc_diff = 1; + + + return; + } + + cpi->skip_false_count++; +#endif +#if 0 + + if (x->mbmi.mode == B_PRED || x->mbmi.mode == SPLITMV) + { + int i, skip = 1; + + for (i = 0; i < 24; i++) + skip &= (!x->block[i].eob); + + if (skip != x->mbmi.mb_skip_coeff) + skip += 0; + + x->mbmi.mb_skip_coeff = skip; + } + else + { + int i, skip = 1; + + for (i = 0; i < 16; i++) + skip &= (x->block[i].eob < 2); + + for (i = 16; i < 25; i++) + skip &= (!x->block[i].eob); + + if (skip != x->mbmi.mb_skip_coeff) + skip += 0; + + x->mbmi.mb_skip_coeff = skip; + } + + vpx_memcpy(cpi->coef_counts_backup, cpi->coef_counts, sizeof(cpi->coef_counts)); +#endif + + if (x->mbmi.mode == B_PRED || x->mbmi.mode == SPLITMV) + { + plane_type = 3; + } + else + { + tokenize2nd_order_b(x->block + 24, t, 1, x->frame_type, + A[Y2CONTEXT] + vp8_block2above[24], L[Y2CONTEXT] + vp8_block2left[24], cpi); + plane_type = 0; + + } + + for (b = 0; b < 16; b++) + tokenize1st_order_b(x->block + b, t, plane_type, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + + for (b = 16; b < 24; b++) + tokenize1st_order_b(x->block + b, t, 2, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + +#if 0 + + if (cpi->common.mb_no_coeff_skip) + { + int skip = 1; + + while ((tp != *t) && skip) + { + skip = (skip && (tp->Token == DCT_EOB_TOKEN)); + tp ++; + } + + if (skip != x->mbmi.mb_skip_coeff) + skip += 0; + + x->mbmi.mb_skip_coeff = skip; + + if (x->mbmi.mb_skip_coeff == 1) + { + x->mbmi.dc_diff = 0; + //redo the coutnts + vpx_memcpy(cpi->coef_counts, cpi->coef_counts_backup, sizeof(cpi->coef_counts)); + + *t = start; + cpi->skip_true_count++; + //skip_true_count++; + } + else + { + + cpi->skip_false_count++; + //skip_false_count++; + } + } + +#endif +} +#endif + +#ifdef ENTROPY_STATS + +void init_context_counters(void) +{ + vpx_memset(context_counters, 0, sizeof(context_counters)); +} + +void print_context_counters() +{ + + int type, band, pt, t; + + FILE *const f = fopen("context.c", "w"); + + fprintf(f, "#include \"entropy.h\"\n"); + + fprintf(f, "\n/* *** GENERATED FILE: DO NOT EDIT *** */\n\n"); + + fprintf(f, "int Contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens];\n\n"); + + fprintf(f, "const int default_contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens] = {"); + +# define Comma( X) (X? ",":"") + + type = 0; + + do + { + fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); + + band = 0; + + do + { + fprintf(f, "%s\n { /* Coeff Band %d */", Comma(band), band); + + pt = 0; + + do + { + fprintf(f, "%s\n {", Comma(pt)); + + t = 0; + + do + { + const _int64 x = context_counters [type] [band] [pt] [t]; + const int y = (int) x; + + assert(x == (_int64) y); /* no overflow handling yet */ + fprintf(f, "%s %d", Comma(t), y); + + } + while (++t < vp8_coef_tokens); + + fprintf(f, "}"); + } + while (++pt < PREV_COEF_CONTEXTS); + + fprintf(f, "\n }"); + + } + while (++band < COEF_BANDS); + + fprintf(f, "\n }"); + } + while (++type < BLOCK_TYPES); + + fprintf(f, "\n};\n"); + fclose(f); +} +#endif + + +void vp8_tokenize_initialize() +{ + fill_value_tokens(); +} + + +static __inline void stuff2nd_order_b +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; + t->section = 11; + t->skip_eob_node = 0; + ++cpi->coef_counts [1] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + + *tp = t; + pt = 0; + *a = *l = pt; + +} + +static __inline void stuff1st_order_b +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [0] [1] [pt]; + t->section = 8; + t->skip_eob_node = 0; + ++cpi->coef_counts [0] [1] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} +static __inline +void stuff1st_order_buv +( + const BLOCKD *const b, + TOKENEXTRA **tp, + const int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ + const FRAME_TYPE frametype, + ENTROPY_CONTEXT *a, + ENTROPY_CONTEXT *l, + VP8_COMP *cpi +) +{ + int pt; /* near block/prev token context index */ + TOKENEXTRA *t = *tp; /* store tokens starting here */ + VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); + (void) frametype; + (void) type; + (void) b; + + t->Token = DCT_EOB_TOKEN; + t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; + t->section = 13; + t->skip_eob_node = 0; + ++cpi->coef_counts[2] [0] [pt] [DCT_EOB_TOKEN]; + ++t; + *tp = t; + pt = 0; /* 0 <-> all coeff data is zero */ + *a = *l = pt; + +} + +void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCKD *x, TOKENEXTRA **t) +{ + //int i; + ENTROPY_CONTEXT **const A = x->above_context; + ENTROPY_CONTEXT(* const L)[4] = x->left_context; + int plane_type; + int b; + + stuff2nd_order_b(x->block + 24, t, 1, x->frame_type, + A[Y2CONTEXT] + vp8_block2above[24], L[Y2CONTEXT] + vp8_block2left[24], cpi); + plane_type = 0; + + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + x->mbmi.dc_diff = 0; + else + x->mbmi.dc_diff = 1; + + + for (b = 0; b < 16; b++) + stuff1st_order_b(x->block + b, t, plane_type, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + + for (b = 16; b < 24; b++) + stuff1st_order_buv(x->block + b, t, 2, x->frame_type, + A[vp8_block2context[b]] + vp8_block2above[b], + L[vp8_block2context[b]] + vp8_block2left[b], cpi); + +} +void vp8_fix_contexts(VP8_COMP *cpi, MACROBLOCKD *x) +{ + x->left_context[Y1CONTEXT][0] = 0; + x->left_context[Y1CONTEXT][1] = 0; + x->left_context[Y1CONTEXT][2] = 0; + x->left_context[Y1CONTEXT][3] = 0; + x->left_context[UCONTEXT][0] = 0; + x->left_context[VCONTEXT][0] = 0; + x->left_context[UCONTEXT][1] = 0; + x->left_context[VCONTEXT][1] = 0; + + x->above_context[Y1CONTEXT][0] = 0; + x->above_context[Y1CONTEXT][1] = 0; + x->above_context[Y1CONTEXT][2] = 0; + x->above_context[Y1CONTEXT][3] = 0; + x->above_context[UCONTEXT][0] = 0; + x->above_context[VCONTEXT][0] = 0; + x->above_context[UCONTEXT][1] = 0; + x->above_context[VCONTEXT][1] = 0; + + if (x->mbmi.mode != B_PRED && x->mbmi.mode != SPLITMV) + { + x->left_context[Y2CONTEXT][0] = 0; + x->above_context[Y2CONTEXT][0] = 0; + } +}
diff --git a/vp8/encoder/tokenize.h b/vp8/encoder/tokenize.h new file mode 100644 index 0000000..02aacc2 --- /dev/null +++ b/vp8/encoder/tokenize.h
@@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef tokenize_h +#define tokenize_h + +#include "entropy.h" +#include "block.h" + +void vp8_tokenize_initialize(); + +typedef struct +{ + int Token; + int Extra; + const vp8_prob *context_tree; + int skip_eob_node; + int section; +} TOKENEXTRA; + +int rd_cost_mby(MACROBLOCKD *); + +#ifdef ENTROPY_STATS +void init_context_counters(); +void print_context_counters(); + +extern _int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [vp8_coef_tokens]; +#endif + + +#endif /* tokenize_h */
diff --git a/vp8/encoder/treewriter.c b/vp8/encoder/treewriter.c new file mode 100644 index 0000000..e398044 --- /dev/null +++ b/vp8/encoder/treewriter.c
@@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "treewriter.h" + +static void cost( + int *const C, + vp8_tree T, + const vp8_prob *const P, + int i, + int c +) +{ + const vp8_prob p = P [i>>1]; + + do + { + const vp8_tree_index j = T[i]; + const int d = c + vp8_cost_bit(p, i & 1); + + if (j <= 0) + C[-j] = d; + else + cost(C, T, P, j, d); + } + while (++i & 1); +} +void vp8_cost_tokens(int *c, const vp8_prob *p, vp8_tree t) +{ + cost(c, t, p, 0, 0); +}
diff --git a/vp8/encoder/treewriter.h b/vp8/encoder/treewriter.h new file mode 100644 index 0000000..05ac74c --- /dev/null +++ b/vp8/encoder/treewriter.h
@@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef __INC_TREEWRITER_H +#define __INC_TREEWRITER_H + +/* Trees map alphabets into huffman-like codes suitable for an arithmetic + bit coder. Timothy S Murphy 11 October 2004 */ + +#include "treecoder.h" + +#include "boolhuff.h" /* for now */ + +typedef BOOL_CODER vp8_writer; + +#define vp8_write vp8_encode_bool +#define vp8_write_literal vp8_encode_value +#define vp8_write_bit( W, V) vp8_write( W, V, vp8_prob_half) + +#define vp8bc_write vp8bc_write_bool +#define vp8bc_write_literal vp8bc_write_bits +#define vp8bc_write_bit( W, V) vp8bc_write_bits( W, V, 1) + + +/* Approximate length of an encoded bool in 256ths of a bit at given prob */ + +#define vp8_cost_zero( x) ( vp8_prob_cost[x]) +#define vp8_cost_one( x) vp8_cost_zero( vp8_complement(x)) + +#define vp8_cost_bit( x, b) vp8_cost_zero( (b)? vp8_complement(x) : (x) ) + +/* VP8BC version is scaled by 2^20 rather than 2^8; see bool_coder.h */ + + +/* Both of these return bits, not scaled bits. */ + +static __inline unsigned int vp8_cost_branch(const unsigned int ct[2], vp8_prob p) +{ + /* Imitate existing calculation */ + + return ((ct[0] * vp8_cost_zero(p)) + + (ct[1] * vp8_cost_one(p))) >> 8; +} + +/* Small functions to write explicit values and tokens, as well as + estimate their lengths. */ + +static __inline void vp8_treed_write +( + vp8_writer *const w, + vp8_tree t, + const vp8_prob *const p, + int v, + int n /* number of bits in v, assumed nonzero */ +) +{ + vp8_tree_index i = 0; + + do + { + const int b = (v >> --n) & 1; + vp8_write(w, b, p[i>>1]); + i = t[i+b]; + } + while (n); +} +static __inline void vp8_write_token +( + vp8_writer *const w, + vp8_tree t, + const vp8_prob *const p, + vp8_token *const x +) +{ + vp8_treed_write(w, t, p, x->value, x->Len); +} + +static __inline int vp8_treed_cost( + vp8_tree t, + const vp8_prob *const p, + int v, + int n /* number of bits in v, assumed nonzero */ +) +{ + int c = 0; + vp8_tree_index i = 0; + + do + { + const int b = (v >> --n) & 1; + c += vp8_cost_bit(p[i>>1], b); + i = t[i+b]; + } + while (n); + + return c; +} +static __inline int vp8_cost_token +( + vp8_tree t, + const vp8_prob *const p, + vp8_token *const x +) +{ + return vp8_treed_cost(t, p, x->value, x->Len); +} + +/* Fill array of costs for all possible token values. */ + +void vp8_cost_tokens( + int *Costs, const vp8_prob *, vp8_tree +); + +#endif
diff --git a/vp8/encoder/variance.h b/vp8/encoder/variance.h new file mode 100644 index 0000000..b3b55c3 --- /dev/null +++ b/vp8/encoder/variance.h
@@ -0,0 +1,327 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef VARIANCE_H +#define VARIANCE_H + +#define prototype_sad(sym)\ + unsigned int (sym)\ + (\ + unsigned char *src_ptr, \ + int source_stride, \ + unsigned char *ref_ptr, \ + int ref_stride, \ + int max_sad\ + ) + +#define prototype_sad_multi_same_address(sym)\ + void (sym)\ + (\ + unsigned char *src_ptr, \ + int source_stride, \ + unsigned char *ref_ptr, \ + int ref_stride, \ + unsigned int *sad_array\ + ) + +#define prototype_sad_multi_dif_address(sym)\ + void (sym)\ + (\ + unsigned char *src_ptr, \ + int source_stride, \ + unsigned char *ref_ptr[4], \ + int ref_stride, \ + unsigned int *sad_array\ + ) + +#define prototype_variance(sym) \ + unsigned int (sym) \ + (\ + unsigned char *src_ptr, \ + int source_stride, \ + unsigned char *ref_ptr, \ + int ref_stride, \ + unsigned int *sse\ + ) + +#define prototype_variance2(sym) \ + unsigned int (sym) \ + (\ + unsigned char *src_ptr, \ + int source_stride, \ + unsigned char *ref_ptr, \ + int ref_stride, \ + unsigned int *sse,\ + int *sum\ + ) + +#define prototype_subpixvariance(sym) \ + unsigned int (sym) \ + ( \ + unsigned char *src_ptr, \ + int source_stride, \ + int xoffset, \ + int yoffset, \ + unsigned char *ref_ptr, \ + int Refstride, \ + unsigned int *sse \ + ); + + +#define prototype_getmbss(sym) unsigned int (sym)(short *) + +#if ARCH_X86 || ARCH_X86_64 +#include "x86/variance_x86.h" +#endif + +#if ARCH_ARM +#include "arm/variance_arm.h" +#endif + +#ifndef vp8_variance_sad4x4 +#define vp8_variance_sad4x4 vp8_sad4x4_c +#endif +extern prototype_sad(vp8_variance_sad4x4); + +#ifndef vp8_variance_sad8x8 +#define vp8_variance_sad8x8 vp8_sad8x8_c +#endif +extern prototype_sad(vp8_variance_sad8x8); + +#ifndef vp8_variance_sad8x16 +#define vp8_variance_sad8x16 vp8_sad8x16_c +#endif +extern prototype_sad(vp8_variance_sad8x16); + +#ifndef vp8_variance_sad16x8 +#define vp8_variance_sad16x8 vp8_sad16x8_c +#endif +extern prototype_sad(vp8_variance_sad16x8); + +#ifndef vp8_variance_sad16x16 +#define vp8_variance_sad16x16 vp8_sad16x16_c +#endif +extern prototype_sad(vp8_variance_sad16x16); + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +#ifndef vp8_variance_sad16x16x3 +#define vp8_variance_sad16x16x3 vp8_sad16x16x3_c +#endif +extern prototype_sad_multi_same_address(vp8_variance_sad16x16x3); + +#ifndef vp8_variance_sad16x8x3 +#define vp8_variance_sad16x8x3 vp8_sad16x8x3_c +#endif +extern prototype_sad_multi_same_address(vp8_variance_sad16x8x3); + +#ifndef vp8_variance_sad8x8x3 +#define vp8_variance_sad8x8x3 vp8_sad8x8x3_c +#endif +extern prototype_sad_multi_same_address(vp8_variance_sad8x8x3); + +#ifndef vp8_variance_sad8x16x3 +#define vp8_variance_sad8x16x3 vp8_sad8x16x3_c +#endif +extern prototype_sad_multi_same_address(vp8_variance_sad8x16x3); + +#ifndef vp8_variance_sad4x4x3 +#define vp8_variance_sad4x4x3 vp8_sad4x4x3_c +#endif +extern prototype_sad_multi_same_address(vp8_variance_sad4x4x3); + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +#ifndef vp8_variance_sad16x16x4d +#define vp8_variance_sad16x16x4d vp8_sad16x16x4d_c +#endif +extern prototype_sad_multi_dif_address(vp8_variance_sad16x16x4d); + +#ifndef vp8_variance_sad16x8x4d +#define vp8_variance_sad16x8x4d vp8_sad16x8x4d_c +#endif +extern prototype_sad_multi_dif_address(vp8_variance_sad16x8x4d); + +#ifndef vp8_variance_sad8x8x4d +#define vp8_variance_sad8x8x4d vp8_sad8x8x4d_c +#endif +extern prototype_sad_multi_dif_address(vp8_variance_sad8x8x4d); + +#ifndef vp8_variance_sad8x16x4d +#define vp8_variance_sad8x16x4d vp8_sad8x16x4d_c +#endif +extern prototype_sad_multi_dif_address(vp8_variance_sad8x16x4d); + +#ifndef vp8_variance_sad4x4x4d +#define vp8_variance_sad4x4x4d vp8_sad4x4x4d_c +#endif +extern prototype_sad_multi_dif_address(vp8_variance_sad4x4x4d); + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +#ifndef vp8_variance_var4x4 +#define vp8_variance_var4x4 vp8_variance4x4_c +#endif +extern prototype_variance(vp8_variance_var4x4); + +#ifndef vp8_variance_var8x8 +#define vp8_variance_var8x8 vp8_variance8x8_c +#endif +extern prototype_variance(vp8_variance_var8x8); + +#ifndef vp8_variance_var8x16 +#define vp8_variance_var8x16 vp8_variance8x16_c +#endif +extern prototype_variance(vp8_variance_var8x16); + +#ifndef vp8_variance_var16x8 +#define vp8_variance_var16x8 vp8_variance16x8_c +#endif +extern prototype_variance(vp8_variance_var16x8); + +#ifndef vp8_variance_var16x16 +#define vp8_variance_var16x16 vp8_variance16x16_c +#endif +extern prototype_variance(vp8_variance_var16x16); + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +#ifndef vp8_variance_subpixvar4x4 +#define vp8_variance_subpixvar4x4 vp8_sub_pixel_variance4x4_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixvar4x4); + +#ifndef vp8_variance_subpixvar8x8 +#define vp8_variance_subpixvar8x8 vp8_sub_pixel_variance8x8_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixvar8x8); + +#ifndef vp8_variance_subpixvar8x16 +#define vp8_variance_subpixvar8x16 vp8_sub_pixel_variance8x16_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixvar8x16); + +#ifndef vp8_variance_subpixvar16x8 +#define vp8_variance_subpixvar16x8 vp8_sub_pixel_variance16x8_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixvar16x8); + +#ifndef vp8_variance_subpixvar16x16 +#define vp8_variance_subpixvar16x16 vp8_sub_pixel_variance16x16_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixvar16x16); + +#ifndef vp8_variance_subpixmse16x16 +#define vp8_variance_subpixmse16x16 vp8_sub_pixel_mse16x16_c +#endif +extern prototype_subpixvariance(vp8_variance_subpixmse16x16); + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +#ifndef vp8_variance_getmbss +#define vp8_variance_getmbss vp8_get_mb_ss_c +#endif +extern prototype_getmbss(vp8_variance_getmbss); + +#ifndef vp8_variance_mse16x16 +#define vp8_variance_mse16x16 vp8_mse16x16_c +#endif +extern prototype_variance(vp8_variance_mse16x16); + +#ifndef vp8_variance_get16x16prederror +#define vp8_variance_get16x16prederror vp8_get16x16pred_error_c +#endif +extern prototype_sad(vp8_variance_get16x16prederror); + +#ifndef vp8_variance_get8x8var +#define vp8_variance_get8x8var vp8_get8x8var_c +#endif +extern prototype_variance2(vp8_variance_get8x8var); + +#ifndef vp8_variance_get16x16var +#define vp8_variance_get16x16var vp8_get16x16var_c +#endif +extern prototype_variance2(vp8_variance_get16x16var); + +#ifndef vp8_variance_get4x4sse_cs +#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_c +#endif +extern prototype_sad(vp8_variance_get4x4sse_cs); + + +typedef prototype_sad(*vp8_sad_fn_t); +typedef prototype_sad_multi_same_address(*vp8_sad_multi_fn_t); +typedef prototype_sad_multi_dif_address(*vp8_sad_multi_d_fn_t); +typedef prototype_variance(*vp8_variance_fn_t); +typedef prototype_variance2(*vp8_variance2_fn_t); +typedef prototype_subpixvariance(*vp8_subpixvariance_fn_t); +typedef prototype_getmbss(*vp8_getmbss_fn_t); +typedef struct +{ + vp8_sad_fn_t sad4x4; + vp8_sad_fn_t sad8x8; + vp8_sad_fn_t sad8x16; + vp8_sad_fn_t sad16x8; + vp8_sad_fn_t sad16x16; + + vp8_variance_fn_t var4x4; + vp8_variance_fn_t var8x8; + vp8_variance_fn_t var8x16; + vp8_variance_fn_t var16x8; + vp8_variance_fn_t var16x16; + + vp8_subpixvariance_fn_t subpixvar4x4; + vp8_subpixvariance_fn_t subpixvar8x8; + vp8_subpixvariance_fn_t subpixvar8x16; + vp8_subpixvariance_fn_t subpixvar16x8; + vp8_subpixvariance_fn_t subpixvar16x16; + vp8_subpixvariance_fn_t subpixmse16x16; + + vp8_getmbss_fn_t getmbss; + vp8_variance_fn_t mse16x16; + + vp8_sad_fn_t get16x16prederror; + vp8_variance2_fn_t get8x8var; + vp8_variance2_fn_t get16x16var; + vp8_sad_fn_t get4x4sse_cs; + + vp8_sad_multi_fn_t sad16x16x3; + vp8_sad_multi_fn_t sad16x8x3; + vp8_sad_multi_fn_t sad8x16x3; + vp8_sad_multi_fn_t sad8x8x3; + vp8_sad_multi_fn_t sad4x4x3; + + vp8_sad_multi_d_fn_t sad16x16x4d; + vp8_sad_multi_d_fn_t sad16x8x4d; + vp8_sad_multi_d_fn_t sad8x16x4d; + vp8_sad_multi_d_fn_t sad8x8x4d; + vp8_sad_multi_d_fn_t sad4x4x4d; + +} vp8_variance_rtcd_vtable_t; + +typedef struct +{ + vp8_sad_fn_t sdf; + vp8_sad_multi_fn_t sdx3f; + vp8_sad_multi_d_fn_t sdx4df; + vp8_variance_fn_t vf; + vp8_subpixvariance_fn_t svf; +} vp8_variance_fn_ptr_t; + +#if CONFIG_RUNTIME_CPU_DETECT +#define VARIANCE_INVOKE(ctx,fn) (ctx)->fn +#else +#define VARIANCE_INVOKE(ctx,fn) vp8_variance_##fn +#endif + +/* TODO: Determine if this USEBILINEAR flag is necessary. */ +#define USEBILINEAR + +#endif
diff --git a/vp8/encoder/variance_c.c b/vp8/encoder/variance_c.c new file mode 100644 index 0000000..85269b9 --- /dev/null +++ b/vp8/encoder/variance_c.c
@@ -0,0 +1,527 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "variance.h" + +const int vp8_six_tap[8][6] = +{ + { 0, 0, 128, 0, 0, 0 }, // note that 1/8 pel positions are just as per alpha -0.5 bicubic + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, // New 1/4 pel 6 tap filter + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, // New 1/2 pel 6 tap filter + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, // New 1/4 pel 6 tap filter + { 0, -1, 12, 123, -6, 0 } +}; + + +#ifdef USEBILINEAR +const int VP8_FILTER_WEIGHT = 128; +const int VP8_FILTER_SHIFT = 7; +const int vp8_bilinear_taps[8][2] = +{ + { 128, 0 }, + { 112, 16 }, + { 96, 32 }, + { 80, 48 }, + { 64, 64 }, + { 48, 80 }, + { 32, 96 }, + { 16, 112 } +}; + +unsigned int vp8_get_mb_ss_c +( + short *src_ptr +) +{ + unsigned int i = 0, sum = 0; + + do + { + sum += (src_ptr[i] * src_ptr[i]); + i++; + } + while (i < 256); + + return sum; +} + + +void vp8_variance( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + int w, + int h, + unsigned int *sse, + int *sum) +{ + int i, j; + int diff; + + *sum = 0; + *sse = 0; + + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + diff = src_ptr[j] - ref_ptr[j]; + *sum += diff; + *sse += diff * diff; + } + + src_ptr += source_stride; + ref_ptr += recon_stride; + } +} + +unsigned int +vp8_get8x8var_c +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +) +{ + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 8, SSE, Sum); + return (*SSE - (((*Sum) * (*Sum)) >> 6)); +} + +unsigned int +vp8_get16x16var_c +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +) +{ + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, SSE, Sum); + return (*SSE - (((*Sum) * (*Sum)) >> 8)); + +} + + + +unsigned int vp8_variance16x16_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); + *sse = var; + return (var - ((avg * avg) >> 8)); +} + +unsigned int vp8_variance8x16_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 16, &var, &avg); + *sse = var; + return (var - ((avg * avg) >> 7)); +} + +unsigned int vp8_variance16x8_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 8, &var, &avg); + *sse = var; + return (var - ((avg * avg) >> 7)); +} + + +unsigned int vp8_variance8x8_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 8, &var, &avg); + *sse = var; + return (var - ((avg * avg) >> 6)); +} + +unsigned int vp8_variance4x4_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 4, 4, &var, &avg); + *sse = var; + return (var - ((avg * avg) >> 4)); +} + + +unsigned int vp8_mse16x16_c( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); + *sse = var; + return var; +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_first_pass + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : INT32 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement first-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Produces INT32 output to retain precision for next pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +void vp8e_filter_block2d_bil_first_pass +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + int pixel_step, + unsigned int output_height, + unsigned int output_width, + const int *vp8_filter +) +{ + unsigned int i, j; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply bilinear filter + output_ptr[j] = (((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2)) >> VP8_FILTER_SHIFT; + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil_second_pass + * + * INPUTS : INT32 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * UINT32 pixel_step : Offset between filter input samples (see notes). + * UINT32 output_height : Input block height. + * UINT32 output_width : Input block width. + * INT32 *vp8_filter : Array of 2 bi-linear filter taps. + * + * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in + * either horizontal or vertical direction to produce the + * filtered output block. Used to implement second-pass + * of 2-D separable filter. + * + * SPECIAL NOTES : Requires 32-bit input as produced by filter_block2d_bil_first_pass. + * Two filter taps should sum to VP8_FILTER_WEIGHT. + * pixel_step defines whether the filter is applied + * horizontally (pixel_step=1) or vertically (pixel_step=stride). + * It defines the offset required to move from one input + * to the next. + * + ****************************************************************************/ +void vp8e_filter_block2d_bil_second_pass +( + unsigned short *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + const int *vp8_filter +) +{ + unsigned int i, j; + int Temp; + + for (i = 0; i < output_height; i++) + { + for (j = 0; j < output_width; j++) + { + // Apply filter + Temp = ((int)src_ptr[0] * vp8_filter[0]) + + ((int)src_ptr[pixel_step] * vp8_filter[1]) + + (VP8_FILTER_WEIGHT / 2); + output_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); + src_ptr++; + } + + // Next row... + src_ptr += src_pixels_per_line - output_width; + output_ptr += output_width; + } +} + + +/**************************************************************************** + * + * ROUTINE : filter_block2d_bil + * + * INPUTS : UINT8 *src_ptr : Pointer to source block. + * UINT32 src_pixels_per_line : Stride of input block. + * INT32 *HFilter : Array of 2 horizontal filter taps. + * INT32 *VFilter : Array of 2 vertical filter taps. + * + * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. + * + * RETURNS : void + * + * FUNCTION : 2-D filters an 8x8 input block by applying a 2-tap + * bi-linear filter horizontally followed by a 2-tap + * bi-linear filter vertically on the result. + * + * SPECIAL NOTES : The intermediate horizontally filtered block must produce + * 1 more point than the input block in each column. This + * is to ensure that the 2-tap filter has one extra data-point + * at the top of each column so filter taps do not extend + * beyond data. Thus the output of the first stage filter + * is an 8x9 (hx_v) block. + * + ****************************************************************************/ +void vp8e_filter_block2d_bil +( + unsigned char *src_ptr, + unsigned char *output_ptr, + unsigned int src_pixels_per_line, + int *HFilter, + int *VFilter +) +{ + + unsigned short FData[20*16]; // Temp data bufffer used in filtering + + // First filter 1-D horizontally... + vp8e_filter_block2d_bil_first_pass(src_ptr, FData, src_pixels_per_line, 1, 9, 8, HFilter); + + // then 1-D vertically... + vp8e_filter_block2d_bil_second_pass(FData, output_ptr, 8, 8, 8, 8, VFilter); +} + + + +unsigned int vp8_sub_pixel_variance4x4_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned char temp2[20*16]; + const int *HFilter, *VFilter; + unsigned short FData3[5*4]; // Temp data bufffer used in filtering + + HFilter = vp8_bilinear_taps[xoffset]; + VFilter = vp8_bilinear_taps[yoffset]; + + // First filter 1d Horizontal + vp8e_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 5, 4, HFilter); + + // Now filter Verticaly + vp8e_filter_block2d_bil_second_pass(FData3, temp2, 4, 4, 4, 4, VFilter); + + return vp8_variance4x4_c(temp2, 4, dst_ptr, dst_pixels_per_line, sse); +} + + +unsigned int vp8_sub_pixel_variance8x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[9*8]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const int *HFilter, *VFilter; + + HFilter = vp8_bilinear_taps[xoffset]; + VFilter = vp8_bilinear_taps[yoffset]; + + vp8e_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 8, HFilter); + vp8e_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 8, 8, VFilter); + + return vp8_variance8x8_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_variance16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[17*16]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const int *HFilter, *VFilter; + + HFilter = vp8_bilinear_taps[xoffset]; + VFilter = vp8_bilinear_taps[yoffset]; + + vp8e_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 16, HFilter); + vp8e_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 16, 16, VFilter); + + return vp8_variance16x16_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_mse16x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_c(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[16*9]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const int *HFilter, *VFilter; + + HFilter = vp8_bilinear_taps[xoffset]; + VFilter = vp8_bilinear_taps[yoffset]; + + vp8e_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 16, HFilter); + vp8e_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 8, 16, VFilter); + + return vp8_variance16x8_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); +} + +unsigned int vp8_sub_pixel_variance8x16_c +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + unsigned short FData3[9*16]; // Temp data bufffer used in filtering + unsigned char temp2[20*16]; + const int *HFilter, *VFilter; + + + HFilter = vp8_bilinear_taps[xoffset]; + VFilter = vp8_bilinear_taps[yoffset]; + + + vp8e_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 8, HFilter); + vp8e_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 16, 8, VFilter); + + return vp8_variance8x16_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); +} +#endif
diff --git a/vp8/encoder/x86/csystemdependent.c b/vp8/encoder/x86/csystemdependent.c new file mode 100644 index 0000000..186ee68 --- /dev/null +++ b/vp8/encoder/x86/csystemdependent.c
@@ -0,0 +1,289 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "variance.h" +#include "onyx_int.h" + +SADFunction *vp8_sad16x16; +SADFunction *vp8_sad16x8; +SADFunction *vp8_sad8x16; +SADFunction *vp8_sad8x8; +SADFunction *vp8_sad4x4; + +variance_function *vp8_variance4x4; +variance_function *vp8_variance8x8; +variance_function *vp8_variance8x16; +variance_function *vp8_variance16x8; +variance_function *vp8_variance16x16; + + +variance_function *vp8_mse16x16; + +sub_pixel_variance_function *vp8_sub_pixel_variance4x4; +sub_pixel_variance_function *vp8_sub_pixel_variance8x8; +sub_pixel_variance_function *vp8_sub_pixel_variance8x16; +sub_pixel_variance_function *vp8_sub_pixel_variance16x8; +sub_pixel_variance_function *vp8_sub_pixel_variance16x16; + +int (*vp8_block_error)(short *, short *); +int (*vp8_mbblock_error)(MACROBLOCK *mb, int dc); +void (*vp8_subtract_mby)(short *diff, unsigned char *src, unsigned char *pred, int stride); + +extern void vp8_subtract_mby_c(short *diff, unsigned char *src, unsigned char *pred, int stride); +extern void vp8_subtract_mby_mmx(short *diff, unsigned char *src, unsigned char *pred, int stride); + +extern int vp8_block_error_c(short *, short *); +extern int vp8_mbblock_error_c(MACROBLOCK *x, int dc); + +extern int vp8_block_error_mmx(short *, short *); +extern int vp8_mbblock_error_mmx(MACROBLOCK *x, int dc); + +extern int vp8_block_error_xmm(short *, short *); +extern int vp8_mbblock_error_xmm(MACROBLOCK *x, int dc); + + + +int (*vp8_mbuverror)(MACROBLOCK *mb); +unsigned int (*vp8_get_mb_ss)(short *); +void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct4x4)(short *input, short *output, int pitch); +void (*vp8_fast_fdct8x4)(short *input, short *output, int pitch); + +void (*vp8_subtract_b)(BLOCK *be, BLOCKD *bd, int pitch); +void (*vp8_subtract_mbuv)(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +void (*vp8_fast_quantize_b)(BLOCK *b, BLOCKD *d); +unsigned int (*vp8_get16x16pred_error)(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +unsigned int (*vp8_get8x8var)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +unsigned int (*vp8_get16x16var)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// c imports +extern int vp8_mbuverror_c(MACROBLOCK *mb); +extern unsigned int vp8_get8x8var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern void vp8_short_fdct4x4_c(short *input, short *output, int pitch); +extern void vp8_short_fdct8x4_c(short *input, short *output, int pitch); +extern void vp8_fast_fdct4x4_c(short *input, short *output, int pitch); +extern void vp8_fast_fdct8x4_c(short *input, short *output, int pitch); + + +extern void vp8_subtract_b_c(BLOCK *be, BLOCKD *bd, int pitch); +extern void vp8_subtract_mbuv_c(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +extern void vp8_fast_quantize_b_c(BLOCK *b, BLOCKD *d); + +extern SADFunction vp8_sad16x16_c; +extern SADFunction vp8_sad16x8_c; +extern SADFunction vp8_sad8x16_c; +extern SADFunction vp8_sad8x8_c; +extern SADFunction vp8_sad4x4_c; + +extern SADFunction vp8_sad16x16_wmt; +extern SADFunction vp8_sad16x8_wmt; +extern SADFunction vp8_sad8x16_wmt; +extern SADFunction vp8_sad8x8_wmt; +extern SADFunction vp8_sad4x4_wmt; + +extern SADFunction vp8_sad16x16_mmx; +extern SADFunction vp8_sad16x8_mmx; +extern SADFunction vp8_sad8x16_mmx; +extern SADFunction vp8_sad8x8_mmx; +extern SADFunction vp8_sad4x4_mmx; + +extern variance_function vp8_variance16x16_c; +extern variance_function vp8_variance8x16_c; +extern variance_function vp8_variance16x8_c; +extern variance_function vp8_variance8x8_c; +extern variance_function vp8_variance4x4_c; +extern variance_function vp8_mse16x16_c; + +extern sub_pixel_variance_function vp8_sub_pixel_variance4x4_c; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x8_c; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x16_c; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x8_c; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x16_c; + +extern unsigned int vp8_get_mb_ss_c(short *); +extern unsigned int vp8_get16x16pred_error_c(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +extern unsigned int vp8_get8x8var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get4x4sse_cs_c(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + +// mmx imports +extern int vp8_mbuverror_mmx(MACROBLOCK *mb); +extern void vp8_fast_quantize_b_mmx(BLOCK *b, BLOCKD *d); +extern void vp8_subtract_b_mmx(BLOCK *be, BLOCKD *bd, int pitch); +extern void vp8_subtract_mbuv_mmx(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride); +extern void vp8_short_fdct4x4_mmx(short *input, short *output, int pitch); +extern void vp8_short_fdct8x4_mmx(short *input, short *output, int pitch); +extern void vp8_fast_fdct8x4_mmx(short *input, short *output, int pitch); +extern void vp8_fast_fdct4x4_mmx(short *input, short *output, int pitch); +extern variance_function vp8_variance4x4_mmx; +extern variance_function vp8_variance8x8_mmx; +extern variance_function vp8_variance8x16_mmx; +extern variance_function vp8_variance16x8_mmx; +extern variance_function vp8_variance16x16_mmx; + +extern variance_function vp8_mse16x16_mmx; +extern sub_pixel_variance_function vp8_sub_pixel_variance4x4_mmx; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x8_mmx; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x16_mmx; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x8_mmx; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x16_mmx; + +extern unsigned int vp8_get16x16pred_error_mmx(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +extern unsigned int vp8_get_mb_ss_mmx(short *); +extern unsigned int vp8_get8x8var_mmx(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_mmx(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get4x4sse_cs_mmx(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); + + +// wmt imports +extern int vp8_mbuverror_xmm(MACROBLOCK *mb); +extern void vp8_fast_quantize_b_sse(BLOCK *b, BLOCKD *d); +extern void vp8_fast_fdct8x4_wmt(short *input, short *output, int pitch); +extern variance_function vp8_variance4x4_wmt; +extern variance_function vp8_variance8x8_wmt; +extern variance_function vp8_variance8x16_wmt; +extern variance_function vp8_variance16x8_wmt; +extern variance_function vp8_variance16x16_wmt; + +extern variance_function vp8_mse16x16_wmt; +extern sub_pixel_variance_function vp8_sub_pixel_variance4x4_wmt; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x8_wmt; +extern sub_pixel_variance_function vp8_sub_pixel_variance8x16_wmt; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x8_wmt; +extern sub_pixel_variance_function vp8_sub_pixel_variance16x16_wmt; +extern unsigned int vp8_get16x16pred_error_sse2(unsigned char *src_ptr, int src_stride, unsigned char *ref_ptr, int ref_stride); +extern unsigned int vp8_get_mb_ss_sse2(short *src_ptr); +extern unsigned int vp8_get8x8var_sse2(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); +extern unsigned int vp8_get16x16var_sse2(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride, unsigned int *SSE, int *Sum); + +extern void vpx_get_processor_flags(int *mmx_enabled, int *xmm_enabled, int *wmt_enabled); + +void vp8_cmachine_specific_config(void) +{ + int mmx_enabled; + int xmm_enabled; + int wmt_enabled; + + vpx_get_processor_flags(&mmx_enabled, &xmm_enabled, &wmt_enabled); + + if (wmt_enabled) // Willamette + { + // Willamette instruction set available: + vp8_mbuverror = vp8_mbuverror_xmm; + vp8_fast_quantize_b = vp8_fast_quantize_b_sse; + vp8_short_fdct4x4 = vp8_short_fdct4x4_mmx; + vp8_short_fdct8x4 = vp8_short_fdct8x4_mmx; + vp8_fast_fdct4x4 = vp8_fast_fdct4x4_mmx; + vp8_fast_fdct8x4 = vp8_fast_fdct8x4_wmt; + vp8_subtract_b = vp8_subtract_b_mmx; + vp8_subtract_mbuv = vp8_subtract_mbuv_mmx; + vp8_variance4x4 = vp8_variance4x4_mmx; + vp8_variance8x8 = vp8_variance8x8_mmx; + vp8_variance8x16 = vp8_variance8x16_wmt; + vp8_variance16x8 = vp8_variance16x8_wmt; + vp8_variance16x16 = vp8_variance16x16_wmt; + vp8_mse16x16 = vp8_mse16x16_wmt; + vp8_sub_pixel_variance4x4 = vp8_sub_pixel_variance4x4_wmt; + vp8_sub_pixel_variance8x8 = vp8_sub_pixel_variance8x8_wmt; + vp8_sub_pixel_variance8x16 = vp8_sub_pixel_variance8x16_wmt; + vp8_sub_pixel_variance16x8 = vp8_sub_pixel_variance16x8_wmt; + vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_wmt; + vp8_get_mb_ss = vp8_get_mb_ss_sse2; + vp8_get16x16pred_error = vp8_get16x16pred_error_sse2; + vp8_get8x8var = vp8_get8x8var_sse2; + vp8_get16x16var = vp8_get16x16var_sse2; + vp8_get4x4sse_cs = vp8_get4x4sse_cs_mmx; + vp8_sad16x16 = vp8_sad16x16_wmt; + vp8_sad16x8 = vp8_sad16x8_wmt; + vp8_sad8x16 = vp8_sad8x16_wmt; + vp8_sad8x8 = vp8_sad8x8_wmt; + vp8_sad4x4 = vp8_sad4x4_wmt; + vp8_block_error = vp8_block_error_xmm; + vp8_mbblock_error = vp8_mbblock_error_xmm; + vp8_subtract_mby = vp8_subtract_mby_mmx; + + } + else if (mmx_enabled) + { + // MMX instruction set available: + vp8_mbuverror = vp8_mbuverror_mmx; + vp8_fast_quantize_b = vp8_fast_quantize_b_mmx; + vp8_short_fdct4x4 = vp8_short_fdct4x4_mmx; + vp8_short_fdct8x4 = vp8_short_fdct8x4_mmx; + vp8_fast_fdct4x4 = vp8_fast_fdct4x4_mmx; + vp8_fast_fdct8x4 = vp8_fast_fdct8x4_mmx; + vp8_subtract_b = vp8_subtract_b_mmx; + vp8_subtract_mbuv = vp8_subtract_mbuv_mmx; + vp8_variance4x4 = vp8_variance4x4_mmx; + vp8_variance8x8 = vp8_variance8x8_mmx; + vp8_variance8x16 = vp8_variance8x16_mmx; + vp8_variance16x8 = vp8_variance16x8_mmx; + vp8_variance16x16 = vp8_variance16x16_mmx; + vp8_mse16x16 = vp8_mse16x16_mmx; + vp8_sub_pixel_variance4x4 = vp8_sub_pixel_variance4x4_mmx; + vp8_sub_pixel_variance8x8 = vp8_sub_pixel_variance8x8_mmx; + vp8_sub_pixel_variance8x16 = vp8_sub_pixel_variance8x16_mmx; + vp8_sub_pixel_variance16x8 = vp8_sub_pixel_variance16x8_mmx; + vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_mmx; + vp8_get_mb_ss = vp8_get_mb_ss_mmx; + vp8_get16x16pred_error = vp8_get16x16pred_error_mmx; + vp8_get8x8var = vp8_get8x8var_mmx; + vp8_get16x16var = vp8_get16x16var_mmx; + vp8_get4x4sse_cs = vp8_get4x4sse_cs_mmx; + vp8_sad16x16 = vp8_sad16x16_mmx; + vp8_sad16x8 = vp8_sad16x8_mmx; + vp8_sad8x16 = vp8_sad8x16_mmx; + vp8_sad8x8 = vp8_sad8x8_mmx; + vp8_sad4x4 = vp8_sad4x4_mmx; + vp8_block_error = vp8_block_error_mmx; + vp8_mbblock_error = vp8_mbblock_error_mmx; + vp8_subtract_mby = vp8_subtract_mby_mmx; + + } + else + { + // Pure C: + vp8_mbuverror = vp8_mbuverror_c; + vp8_fast_quantize_b = vp8_fast_quantize_b_c; + vp8_short_fdct4x4 = vp8_short_fdct4x4_c; + vp8_short_fdct8x4 = vp8_short_fdct8x4_c; + vp8_fast_fdct4x4 = vp8_fast_fdct4x4_c; + vp8_fast_fdct8x4 = vp8_fast_fdct8x4_c; + vp8_subtract_b = vp8_subtract_b_c; + vp8_subtract_mbuv = vp8_subtract_mbuv_c; + vp8_variance4x4 = vp8_variance4x4_c; + vp8_variance8x8 = vp8_variance8x8_c; + vp8_variance8x16 = vp8_variance8x16_c; + vp8_variance16x8 = vp8_variance16x8_c; + vp8_variance16x16 = vp8_variance16x16_c; + vp8_mse16x16 = vp8_mse16x16_c; + vp8_sub_pixel_variance4x4 = vp8_sub_pixel_variance4x4_c; + vp8_sub_pixel_variance8x8 = vp8_sub_pixel_variance8x8_c; + vp8_sub_pixel_variance8x16 = vp8_sub_pixel_variance8x16_c; + vp8_sub_pixel_variance16x8 = vp8_sub_pixel_variance16x8_c; + vp8_sub_pixel_variance16x16 = vp8_sub_pixel_variance16x16_c; + vp8_get_mb_ss = vp8_get_mb_ss_c; + vp8_get16x16pred_error = vp8_get16x16pred_error_c; + vp8_get8x8var = vp8_get8x8var_c; + vp8_get16x16var = vp8_get16x16var_c; + vp8_get4x4sse_cs = vp8_get4x4sse_cs_c; + vp8_sad16x16 = vp8_sad16x16_c; + vp8_sad16x8 = vp8_sad16x8_c; + vp8_sad8x16 = vp8_sad8x16_c; + vp8_sad8x8 = vp8_sad8x8_c; + vp8_sad4x4 = vp8_sad4x4_c; + vp8_block_error = vp8_block_error_c; + vp8_mbblock_error = vp8_mbblock_error_c; + vp8_subtract_mby = vp8_subtract_mby_c; + } + +}
diff --git a/vp8/encoder/x86/dct_mmx.asm b/vp8/encoder/x86/dct_mmx.asm new file mode 100644 index 0000000..e134237 --- /dev/null +++ b/vp8/encoder/x86/dct_mmx.asm
@@ -0,0 +1,846 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +section .text + global sym(vp8_short_fdct4x4_mmx) + global sym(vp8_fast_fdct4x4_mmx) + global sym(vp8_fast_fdct8x4_wmt) + + +%define DCTCONSTANTSBITS (16) +%define DCTROUNDINGVALUE (1<< (DCTCONSTANTSBITS-1)) +%define x_c1 (60547) ; cos(pi /8) * (1<<15) +%define x_c2 (46341) ; cos(pi*2/8) * (1<<15) +%define x_c3 (25080) ; cos(pi*3/8) * (1<<15) + + +%define _1STSTAGESHIFT 14 +%define _2NDSTAGESHIFT 16 + +; using matrix multiply with source and destbuffer has a pitch +;void vp8_short_fdct4x4_mmx(short *input, short *output, int pitch) +sym(vp8_short_fdct4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;input + mov rdi, arg(1) ;output + + movsxd rax, dword ptr arg(2) ;pitch + lea rdx, [dct_matrix GLOBAL] + + movq mm0, [rsi ] + movq mm1, [rsi + rax] + + movq mm2, [rsi + rax*2] + lea rsi, [rsi + rax*2] + + movq mm3, [rsi + rax] + + ; first column + movq mm4, mm0 + movq mm7, [rdx] + + pmaddwd mm4, mm7 + movq mm5, mm1 + + pmaddwd mm5, mm7 + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + + pmaddwd mm5, mm7 + movq mm6, mm3 + + pmaddwd mm6, mm7 + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct1st_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _1STSTAGESHIFT + psrad mm5, _1STSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi], mm4 + + ;second column + movq mm4, mm0 + + pmaddwd mm4, [rdx+8] + movq mm5, mm1 + + pmaddwd mm5, [rdx+8] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx+8] + movq mm6, mm3 + + pmaddwd mm6, [rdx+8] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct1st_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _1STSTAGESHIFT + psrad mm5, _1STSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi+8], mm4 + + + ;third column + movq mm4, mm0 + + pmaddwd mm4, [rdx+16] + movq mm5, mm1 + + pmaddwd mm5, [rdx+16] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx+16] + movq mm6, mm3 + + pmaddwd mm6, [rdx+16] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct1st_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _1STSTAGESHIFT + psrad mm5, _1STSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi+16], mm4 + + ;fourth column (this is the last column, so we do not have save the source any more) + + pmaddwd mm0, [rdx+24] + + pmaddwd mm1, [rdx+24] + movq mm6, mm0 + + punpckldq mm0, mm1 + punpckhdq mm6, mm1 + + paddd mm0, mm6 + + pmaddwd mm2, [rdx+24] + + pmaddwd mm3, [rdx+24] + movq mm7, mm2 + + punpckldq mm2, mm3 + punpckhdq mm7, mm3 + + paddd mm2, mm7 + movq mm6, [dct1st_stage_rounding_mmx GLOBAL] + + paddd mm0, mm6 + paddd mm2, mm6 + + psrad mm0, _1STSTAGESHIFT + psrad mm2, _1STSTAGESHIFT + + packssdw mm0, mm2 + + movq mm3, mm0 + + ; done with one pass + ; now start second pass + movq mm0, [rdi ] + movq mm1, [rdi+ 8] + movq mm2, [rdi+ 16] + + movq mm4, mm0 + + pmaddwd mm4, [rdx] + movq mm5, mm1 + + pmaddwd mm5, [rdx] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx] + movq mm6, mm3 + + pmaddwd mm6, [rdx] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct2nd_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _2NDSTAGESHIFT + psrad mm5, _2NDSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi], mm4 + + ;second column + movq mm4, mm0 + + pmaddwd mm4, [rdx+8] + movq mm5, mm1 + + pmaddwd mm5, [rdx+8] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx+8] + movq mm6, mm3 + + pmaddwd mm6, [rdx+8] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct2nd_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _2NDSTAGESHIFT + psrad mm5, _2NDSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi+8], mm4 + + + ;third column + movq mm4, mm0 + + pmaddwd mm4, [rdx+16] + movq mm5, mm1 + + pmaddwd mm5, [rdx+16] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx+16] + movq mm6, mm3 + + pmaddwd mm6, [rdx+16] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct2nd_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _2NDSTAGESHIFT + psrad mm5, _2NDSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi+16], mm4 + + ;fourth column + movq mm4, mm0 + + pmaddwd mm4, [rdx+24] + movq mm5, mm1 + + pmaddwd mm5, [rdx+24] + movq mm6, mm4 + + punpckldq mm4, mm5 + punpckhdq mm6, mm5 + + paddd mm4, mm6 + movq mm5, mm2 + + pmaddwd mm5, [rdx+24] + movq mm6, mm3 + + pmaddwd mm6, [rdx+24] + movq mm7, mm5 + + punpckldq mm5, mm6 + punpckhdq mm7, mm6 + + paddd mm5, mm7 + movq mm6, [dct2nd_stage_rounding_mmx GLOBAL] + + paddd mm4, mm6 + paddd mm5, mm6 + + psrad mm4, _2NDSTAGESHIFT + psrad mm5, _2NDSTAGESHIFT + + packssdw mm4, mm5 + movq [rdi+24], mm4 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_fast_fdct4x4_mmx(short *input, short *output, int pitch) +sym(vp8_fast_fdct4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;input + mov rdi, arg(1) ;output + + lea rdx, [dct_const_mmx GLOBAL] + movsxd rax, dword ptr arg(2) ;pitch + + lea rcx, [rsi + rax*2] + ; read the input data + movq mm0, [rsi] + movq mm1, [rsi + rax ] + + movq mm2, [rcx] + movq mm3, [rcx + rax] + ; get the constants + ;shift to left by 1 for prescision + paddw mm0, mm0 + paddw mm1, mm1 + + psllw mm2, 1 + psllw mm3, 1 + + ; transpose for the second stage + movq mm4, mm0 ; 00 01 02 03 + movq mm5, mm2 ; 10 11 12 03 + + punpcklwd mm0, mm1 ; 00 10 01 11 + punpckhwd mm4, mm1 ; 02 12 03 13 + + punpcklwd mm2, mm3 ; 20 30 21 31 + punpckhwd mm5, mm3 ; 22 32 23 33 + + + movq mm1, mm0 ; 00 10 01 11 + punpckldq mm0, mm2 ; 00 10 20 30 + + punpckhdq mm1, mm2 ; 01 11 21 31 + + movq mm2, mm4 ; 02 12 03 13 + punpckldq mm2, mm5 ; 02 12 22 32 + + punpckhdq mm4, mm5 ; 03 13 23 33 + movq mm3, mm4 + + + ; first stage + movq mm5, mm0 + movq mm4, mm1 + + paddw mm0, mm3 ; a = 0 + 3 + paddw mm1, mm2 ; b = 1 + 2 + + psubw mm4, mm2 ; c = 1 - 2 + psubw mm5, mm3 ; d = 0 - 3 + + + ; output 0 and 2 + movq mm6, [rdx + 16] ; c2 + movq mm2, mm0 ; a + + paddw mm0, mm1 ; a + b + psubw mm2, mm1 ; a - b + + movq mm1, mm0 ; a + b + pmulhw mm0, mm6 ; 00 01 02 03 + + paddw mm0, mm1 ; output 00 01 02 03 + pmulhw mm6, mm2 ; 20 21 22 23 + + paddw mm2, mm6 ; output 20 21 22 23 + + ; output 1 and 3 + movq mm6, [rdx + 8] ; c1 + movq mm7, [rdx + 24] ; c3 + + movq mm1, mm4 ; c + movq mm3, mm5 ; d + + pmulhw mm1, mm7 ; c * c3 + pmulhw mm3, mm6 ; d * c1 + + paddw mm3, mm5 ; d * c1 rounded + paddw mm1, mm3 ; output 10 11 12 13 + + movq mm3, mm4 ; c + pmulhw mm5, mm7 ; d * c3 + + pmulhw mm4, mm6 ; c * c1 + paddw mm3, mm4 ; round c* c1 + + psubw mm5, mm3 ; output 30 31 32 33 + movq mm3, mm5 + + + ; done with vertical + ; transpose for the second stage + movq mm4, mm0 ; 00 01 02 03 + movq mm5, mm2 ; 10 11 12 03 + + punpcklwd mm0, mm1 ; 00 10 01 11 + punpckhwd mm4, mm1 ; 02 12 03 13 + + punpcklwd mm2, mm3 ; 20 30 21 31 + punpckhwd mm5, mm3 ; 22 32 23 33 + + + movq mm1, mm0 ; 00 10 01 11 + punpckldq mm0, mm2 ; 00 10 20 30 + + punpckhdq mm1, mm2 ; 01 11 21 31 + + movq mm2, mm4 ; 02 12 03 13 + punpckldq mm2, mm5 ; 02 12 22 32 + + punpckhdq mm4, mm5 ; 03 13 23 33 + movq mm3, mm4 + + + ; first stage + movq mm5, mm0 + movq mm4, mm1 + + paddw mm0, mm3 ; a = 0 + 3 + paddw mm1, mm2 ; b = 1 + 2 + + psubw mm4, mm2 ; c = 1 - 2 + psubw mm5, mm3 ; d = 0 - 3 + + + ; output 0 and 2 + movq mm6, [rdx + 16] ; c2 + movq mm2, mm0 ; a + paddw mm0, mm1 ; a + b + + psubw mm2, mm1 ; a - b + + movq mm1, mm0 ; a + b + pmulhw mm0, mm6 ; 00 01 02 03 + + paddw mm0, mm1 ; output 00 01 02 03 + pmulhw mm6, mm2 ; 20 21 22 23 + + paddw mm2, mm6 ; output 20 21 22 23 + + + ; output 1 and 3 + movq mm6, [rdx + 8] ; c1 + movq mm7, [rdx + 24] ; c3 + + movq mm1, mm4 ; c + movq mm3, mm5 ; d + + pmulhw mm1, mm7 ; c * c3 + pmulhw mm3, mm6 ; d * c1 + + paddw mm3, mm5 ; d * c1 rounded + paddw mm1, mm3 ; output 10 11 12 13 + + movq mm3, mm4 ; c + pmulhw mm5, mm7 ; d * c3 + + pmulhw mm4, mm6 ; c * c1 + paddw mm3, mm4 ; round c* c1 + + psubw mm5, mm3 ; output 30 31 32 33 + movq mm3, mm5 + ; done with vertical + + pcmpeqw mm4, mm4 + pcmpeqw mm5, mm5 + psrlw mm4, 15 + psrlw mm5, 15 + + paddw mm0, mm4 + paddw mm1, mm5 + paddw mm2, mm4 + paddw mm3, mm5 + + psraw mm0, 1 + psraw mm1, 1 + psraw mm2, 1 + psraw mm3, 1 + + movq [rdi ], mm0 + movq [rdi+ 8], mm1 + movq [rdi+16], mm2 + movq [rdi+24], mm3 + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_fast_fdct8x4_wmt(short *input, short *output, int pitch) +sym(vp8_fast_fdct8x4_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + GET_GOT rbx + push rsi + push rdi + ; end prolog + mov rsi, arg(0) ;input + mov rdi, arg(1) ;output + + lea rdx, [dct_const_xmm GLOBAL] + movsxd rax, dword ptr arg(2) ;pitch + + lea rcx, [rsi + rax*2] + ; read the input data + movdqa xmm0, [rsi] + movdqa xmm2, [rsi + rax] + + movdqa xmm4, [rcx] + movdqa xmm3, [rcx + rax] + ; get the constants + ;shift to left by 1 for prescision + psllw xmm0, 1 + psllw xmm2, 1 + + psllw xmm4, 1 + psllw xmm3, 1 + + ; transpose for the second stage + movdqa xmm1, xmm0 ; 00 01 02 03 04 05 06 07 + movdqa xmm5, xmm4 ; 20 21 22 23 24 25 26 27 + + punpcklwd xmm0, xmm2 ; 00 10 01 11 02 12 03 13 + punpckhwd xmm1, xmm2 ; 04 14 05 15 06 16 07 17 + + punpcklwd xmm4, xmm3 ; 20 30 21 31 22 32 23 33 + punpckhwd xmm5, xmm3 ; 24 34 25 35 26 36 27 37 + + movdqa xmm2, xmm0 ; 00 10 01 11 02 12 03 13 + punpckldq xmm0, xmm4 ; 00 10 20 30 01 11 21 31 + + punpckhdq xmm2, xmm4 ; 02 12 22 32 03 13 23 33 + + + movdqa xmm4, xmm1 ; 04 14 05 15 06 16 07 17 + punpckldq xmm4, xmm5 ; 04 14 24 34 05 15 25 35 + + punpckhdq xmm1, xmm5 ; 06 16 26 36 07 17 27 37 + movdqa xmm3, xmm2 ; 02 12 22 32 03 13 23 33 + + punpckhqdq xmm3, xmm1 ; 03 13 23 33 07 17 27 37 + punpcklqdq xmm2, xmm1 ; 02 12 22 32 06 16 26 36 + + movdqa xmm1, xmm0 ; 00 10 20 30 01 11 21 31 + punpcklqdq xmm0, xmm4 ; 00 10 20 30 04 14 24 34 + + punpckhqdq xmm1, xmm4 ; 01 11 21 32 05 15 25 35 + + ; xmm0 0 + ; xmm1 1 + ; xmm2 2 + ; xmm3 3 + + ; first stage + movdqa xmm5, xmm0 + movdqa xmm4, xmm1 + + paddw xmm0, xmm3 ; a = 0 + 3 + paddw xmm1, xmm2 ; b = 1 + 2 + + psubw xmm4, xmm2 ; c = 1 - 2 + psubw xmm5, xmm3 ; d = 0 - 3 + + + ; output 0 and 2 + movdqa xmm6, [rdx + 32] ; c2 + movdqa xmm2, xmm0 ; a + + paddw xmm0, xmm1 ; a + b + psubw xmm2, xmm1 ; a - b + + movdqa xmm1, xmm0 ; a + b + pmulhw xmm0, xmm6 ; 00 01 02 03 + + paddw xmm0, xmm1 ; output 00 01 02 03 + pmulhw xmm6, xmm2 ; 20 21 22 23 + + paddw xmm2, xmm6 ; output 20 21 22 23 + + ; output 1 and 3 + movdqa xmm6, [rdx + 16] ; c1 + movdqa xmm7, [rdx + 48] ; c3 + + movdqa xmm1, xmm4 ; c + movdqa xmm3, xmm5 ; d + + pmulhw xmm1, xmm7 ; c * c3 + pmulhw xmm3, xmm6 ; d * c1 + + paddw xmm3, xmm5 ; d * c1 rounded + paddw xmm1, xmm3 ; output 10 11 12 13 + + movdqa xmm3, xmm4 ; c + pmulhw xmm5, xmm7 ; d * c3 + + pmulhw xmm4, xmm6 ; c * c1 + paddw xmm3, xmm4 ; round c* c1 + + psubw xmm5, xmm3 ; output 30 31 32 33 + movdqa xmm3, xmm5 + + + ; done with vertical + ; transpose for the second stage + movdqa xmm4, xmm2 ; 02 12 22 32 06 16 26 36 + movdqa xmm2, xmm1 ; 01 11 21 31 05 15 25 35 + + movdqa xmm1, xmm0 ; 00 10 20 30 04 14 24 34 + movdqa xmm5, xmm4 ; 02 12 22 32 06 16 26 36 + + punpcklwd xmm0, xmm2 ; 00 01 10 11 20 21 30 31 + punpckhwd xmm1, xmm2 ; 04 05 14 15 24 25 34 35 + + punpcklwd xmm4, xmm3 ; 02 03 12 13 22 23 32 33 + punpckhwd xmm5, xmm3 ; 06 07 16 17 26 27 36 37 + + movdqa xmm2, xmm0 ; 00 01 10 11 20 21 30 31 + punpckldq xmm0, xmm4 ; 00 01 02 03 10 11 12 13 + + punpckhdq xmm2, xmm4 ; 20 21 22 23 30 31 32 33 + + + movdqa xmm4, xmm1 ; 04 05 14 15 24 25 34 35 + punpckldq xmm4, xmm5 ; 04 05 06 07 14 15 16 17 + + punpckhdq xmm1, xmm5 ; 24 25 26 27 34 35 36 37 + movdqa xmm3, xmm2 ; 20 21 22 23 30 31 32 33 + + punpckhqdq xmm3, xmm1 ; 30 31 32 33 34 35 36 37 + punpcklqdq xmm2, xmm1 ; 20 21 22 23 24 25 26 27 + + movdqa xmm1, xmm0 ; 00 01 02 03 10 11 12 13 + punpcklqdq xmm0, xmm4 ; 00 01 02 03 04 05 06 07 + + punpckhqdq xmm1, xmm4 ; 10 11 12 13 14 15 16 17 + + ; first stage + movdqa xmm5, xmm0 + movdqa xmm4, xmm1 + + paddw xmm0, xmm3 ; a = 0 + 3 + paddw xmm1, xmm2 ; b = 1 + 2 + + psubw xmm4, xmm2 ; c = 1 - 2 + psubw xmm5, xmm3 ; d = 0 - 3 + + + ; output 0 and 2 + movdqa xmm6, [rdx + 32] ; c2 + movdqa xmm2, xmm0 ; a + + paddw xmm0, xmm1 ; a + b + psubw xmm2, xmm1 ; a - b + + movdqa xmm1, xmm0 ; a + b + pmulhw xmm0, xmm6 ; 00 01 02 03 + + paddw xmm0, xmm1 ; output 00 01 02 03 + pmulhw xmm6, xmm2 ; 20 21 22 23 + + paddw xmm2, xmm6 ; output 20 21 22 23 + + ; output 1 and 3 + movdqa xmm6, [rdx + 16] ; c1 + movdqa xmm7, [rdx + 48] ; c3 + + movdqa xmm1, xmm4 ; c + movdqa xmm3, xmm5 ; d + + pmulhw xmm1, xmm7 ; c * c3 + pmulhw xmm3, xmm6 ; d * c1 + + paddw xmm3, xmm5 ; d * c1 rounded + paddw xmm1, xmm3 ; output 10 11 12 13 + + movdqa xmm3, xmm4 ; c + pmulhw xmm5, xmm7 ; d * c3 + + pmulhw xmm4, xmm6 ; c * c1 + paddw xmm3, xmm4 ; round c* c1 + + psubw xmm5, xmm3 ; output 30 31 32 33 + movdqa xmm3, xmm5 + ; done with vertical + + + pcmpeqw xmm4, xmm4 + pcmpeqw xmm5, xmm5; + psrlw xmm4, 15 + psrlw xmm5, 15 + + paddw xmm0, xmm4 + paddw xmm1, xmm5 + paddw xmm2, xmm4 + paddw xmm3, xmm5 + + psraw xmm0, 1 + psraw xmm1, 1 + psraw xmm2, 1 + psraw xmm3, 1 + + movq QWORD PTR[rdi ], xmm0 + movq QWORD PTR[rdi+ 8], xmm1 + movq QWORD PTR[rdi+16], xmm2 + movq QWORD PTR[rdi+24], xmm3 + + psrldq xmm0, 8 + psrldq xmm1, 8 + psrldq xmm2, 8 + psrldq xmm3, 8 + + movq QWORD PTR[rdi+32], xmm0 + movq QWORD PTR[rdi+40], xmm1 + movq QWORD PTR[rdi+48], xmm2 + movq QWORD PTR[rdi+56], xmm3 + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +;static const unsigned int dct1st_stage_rounding_mmx[2] = +align 16 +dct1st_stage_rounding_mmx: + times 2 dd 8192 + + +;static const unsigned int dct2nd_stage_rounding_mmx[2] = +align 16 +dct2nd_stage_rounding_mmx: + times 2 dd 32768 + + +;static const short dct_matrix[4][4]= +align 16 +dct_matrix: + times 4 dw 23170 + + dw 30274 + dw 12540 + dw -12540 + dw -30274 + + dw 23170 + times 2 dw -23170 + dw 23170 + + dw 12540 + dw -30274 + dw 30274 + dw -12540 + + +;static const unsigned short dct_const_mmx[4 * 4]= +align 16 +dct_const_mmx: + times 4 dw 0 + times 4 dw 60547 + times 4 dw 46341 + times 4 dw 25080 + + +;static const unsigned short dct_const_xmm[8 * 4]= +align 16 +dct_const_xmm: + times 8 dw 0 + times 8 dw 60547 + times 8 dw 46341 + times 8 dw 25080
diff --git a/vp8/encoder/x86/dct_sse2.asm b/vp8/encoder/x86/dct_sse2.asm new file mode 100644 index 0000000..3e5e9a7 --- /dev/null +++ b/vp8/encoder/x86/dct_sse2.asm
@@ -0,0 +1,260 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +global sym(vp8_short_fdct4x4_wmt) + +%define DCTCONSTANTSBITS (16) +%define DCTROUNDINGVALUE (1<< (DCTCONSTANTSBITS-1)) +%define x_c1 (60547) ; cos(pi /8) * (1<<15) +%define x_c2 (46341) ; cos(pi*2/8) * (1<<15) +%define x_c3 (25080) ; cos(pi*3/8) * (1<<15) + +%define _1STSTAGESHIFT 14 +%define _2NDSTAGESHIFT 16 + + +;; using matrix multiply +;void vp8_short_fdct4x4_wmt(short *input, short *output) +sym(vp8_short_fdct4x4_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + GET_GOT rbx + ; end prolog + + mov rax, arg(0) ;input + mov rcx, arg(1) ;output + + lea rdx, [dct_matrix_sse2 GLOBAL] + + movdqu xmm0, [rax ] + movdqu xmm1, [rax+16] + + ; first column + movdqa xmm2, xmm0 + movdqa xmm7, [rdx] + + pmaddwd xmm2, xmm7 + movdqa xmm3, xmm1 + + pmaddwd xmm3, xmm7 + movdqa xmm4, xmm2 + + punpckldq xmm2, xmm3 + punpckhdq xmm4, xmm3 + + movdqa xmm3, xmm2 + punpckldq xmm2, xmm4 + + punpckhdq xmm3, xmm4 + paddd xmm2, xmm3 + + + paddd xmm2, XMMWORD PTR [dct1st_stage_rounding_sse2 GLOBAL] + psrad xmm2, _1STSTAGESHIFT + ;second column + movdqa xmm3, xmm0 + pmaddwd xmm3, [rdx+16] + + movdqa xmm4, xmm1 + pmaddwd xmm4, [rdx+16] + + movdqa xmm5, xmm3 + punpckldq xmm3, xmm4 + + punpckhdq xmm5, xmm4 + movdqa xmm4, xmm3 + + punpckldq xmm3, xmm5 + punpckhdq xmm4, xmm5 + + paddd xmm3, xmm4 + paddd xmm3, XMMWORD PTR [dct1st_stage_rounding_sse2 GLOBAL] + + + psrad xmm3, _1STSTAGESHIFT + packssdw xmm2, xmm3 + + ;third column + movdqa xmm3, xmm0 + pmaddwd xmm3, [rdx+32] + + movdqa xmm4, xmm1 + pmaddwd xmm4, [rdx+32] + + movdqa xmm5, xmm3 + punpckldq xmm3, xmm4 + + punpckhdq xmm5, xmm4 + movdqa xmm4, xmm3 + + punpckldq xmm3, xmm5 + punpckhdq xmm4, xmm5 + + paddd xmm3, xmm4 + paddd xmm3, XMMWORD PTR [dct1st_stage_rounding_sse2 GLOBAL] + + psrad xmm3, _1STSTAGESHIFT + + ;fourth column (this is the last column, so we do not have save the source any more) + pmaddwd xmm0, [rdx+48] + pmaddwd xmm1, [rdx+48] + + movdqa xmm4, xmm0 + punpckldq xmm0, xmm1 + + punpckhdq xmm4, xmm1 + movdqa xmm1, xmm0 + + punpckldq xmm0, xmm4 + punpckhdq xmm1, xmm4 + + paddd xmm0, xmm1 + paddd xmm0, XMMWORD PTR [dct1st_stage_rounding_sse2 GLOBAL] + + + psrad xmm0, _1STSTAGESHIFT + packssdw xmm3, xmm0 + ; done with one pass + ; now start second pass + movdqa xmm0, xmm2 + movdqa xmm1, xmm3 + + pmaddwd xmm2, xmm7 + pmaddwd xmm3, xmm7 + + movdqa xmm4, xmm2 + punpckldq xmm2, xmm3 + + punpckhdq xmm4, xmm3 + movdqa xmm3, xmm2 + + punpckldq xmm2, xmm4 + punpckhdq xmm3, xmm4 + + paddd xmm2, xmm3 + paddd xmm2, XMMWORD PTR [dct2nd_stage_rounding_sse2 GLOBAL] + + psrad xmm2, _2NDSTAGESHIFT + + ;second column + movdqa xmm3, xmm0 + pmaddwd xmm3, [rdx+16] + + movdqa xmm4, xmm1 + pmaddwd xmm4, [rdx+16] + + movdqa xmm5, xmm3 + punpckldq xmm3, xmm4 + + punpckhdq xmm5, xmm4 + movdqa xmm4, xmm3 + + punpckldq xmm3, xmm5 + punpckhdq xmm4, xmm5 + + paddd xmm3, xmm4 + paddd xmm3, XMMWORD PTR [dct2nd_stage_rounding_sse2 GLOBAL] + + psrad xmm3, _2NDSTAGESHIFT + packssdw xmm2, xmm3 + + movdqu [rcx], xmm2 + ;third column + movdqa xmm3, xmm0 + pmaddwd xmm3, [rdx+32] + + movdqa xmm4, xmm1 + pmaddwd xmm4, [rdx+32] + + movdqa xmm5, xmm3 + punpckldq xmm3, xmm4 + + punpckhdq xmm5, xmm4 + movdqa xmm4, xmm3 + + punpckldq xmm3, xmm5 + punpckhdq xmm4, xmm5 + + paddd xmm3, xmm4 + paddd xmm3, XMMWORD PTR [dct2nd_stage_rounding_sse2 GLOBAL] + + psrad xmm3, _2NDSTAGESHIFT + ;fourth column + pmaddwd xmm0, [rdx+48] + pmaddwd xmm1, [rdx+48] + + movdqa xmm4, xmm0 + punpckldq xmm0, xmm1 + + punpckhdq xmm4, xmm1 + movdqa xmm1, xmm0 + + punpckldq xmm0, xmm4 + punpckhdq xmm1, xmm4 + + paddd xmm0, xmm1 + paddd xmm0, XMMWORD PTR [dct2nd_stage_rounding_sse2 GLOBAL] + + psrad xmm0, _2NDSTAGESHIFT + packssdw xmm3, xmm0 + + movdqu [rcx+16], xmm3 + + mov rsp, rbp + ; begin epilog + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +;static unsigned int dct1st_stage_rounding_sse2[4] = +align 16 +dct1st_stage_rounding_sse2: + times 4 dd 8192 + + +;static unsigned int dct2nd_stage_rounding_sse2[4] = +align 16 +dct2nd_stage_rounding_sse2: + times 4 dd 32768 + +;static short dct_matrix_sse2[4][8]= +align 16 +dct_matrix_sse2: + times 8 dw 23170 + + dw 30274 + dw 12540 + dw -12540 + dw -30274 + dw 30274 + dw 12540 + dw -12540 + dw -30274 + + dw 23170 + times 2 dw -23170 + times 2 dw 23170 + times 2 dw -23170 + dw 23170 + + dw 12540 + dw -30274 + dw 30274 + dw -12540 + dw 12540 + dw -30274 + dw 30274 + dw -12540
diff --git a/vp8/encoder/x86/dct_x86.h b/vp8/encoder/x86/dct_x86.h new file mode 100644 index 0000000..bc80e64 --- /dev/null +++ b/vp8/encoder/x86/dct_x86.h
@@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef DCT_X86_H +#define DCT_X86_H + + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ +#if HAVE_MMX +extern prototype_fdct(vp8_short_fdct4x4_mmx); +extern prototype_fdct(vp8_short_fdct8x4_mmx); +extern prototype_fdct(vp8_fast_fdct4x4_mmx); +extern prototype_fdct(vp8_fast_fdct8x4_mmx); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_fdct_short4x4 +#define vp8_fdct_short4x4 vp8_short_fdct4x4_mmx + +#undef vp8_fdct_short8x4 +#define vp8_fdct_short8x4 vp8_short_fdct8x4_mmx + +#undef vp8_fdct_fast4x4 +#define vp8_fdct_fast4x4 vp8_fast_fdct4x4_mmx + +#undef vp8_fdct_fast8x4 +#define vp8_fdct_fast8x4 vp8_fast_fdct8x4_mmx + +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_fdct(vp8_short_fdct4x4_wmt); +extern prototype_fdct(vp8_short_fdct8x4_wmt); +extern prototype_fdct(vp8_fast_fdct8x4_wmt); + +extern prototype_fdct(vp8_short_walsh4x4_sse2); + +#if !CONFIG_RUNTIME_CPU_DETECT + +#if 0 +/* short SSE2 DCT currently disabled, does not match the MMX version */ +#undef vp8_fdct_short4x4 +#define vp8_fdct_short4x4 vp8_short_fdct4x4_wmt + +#undef vp8_fdct_short8x4 +#define vp8_fdct_short8x4 vp8_short_fdct8x4_wmt +#endif + +#undef vp8_fdct_fast8x4 +#define vp8_fdct_fast8x4 vp8_fast_fdct8x4_wmt + +#undef vp8_fdct_walsh_short4x4 +#define vp8_fdct_walsh_short4x4 vp8_short_walsh4x4_sse2 + +#endif + + +#endif + +#endif
diff --git a/vp8/encoder/x86/encodemb_x86.h b/vp8/encoder/x86/encodemb_x86.h new file mode 100644 index 0000000..9397a6c --- /dev/null +++ b/vp8/encoder/x86/encodemb_x86.h
@@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef ENCODEMB_X86_H +#define ENCODEMB_X86_H + + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ +#if HAVE_MMX +extern prototype_berr(vp8_block_error_mmx); +extern prototype_mberr(vp8_mbblock_error_mmx); +extern prototype_mbuverr(vp8_mbuverror_mmx); +extern prototype_subb(vp8_subtract_b_mmx); +extern prototype_submby(vp8_subtract_mby_mmx); +extern prototype_submbuv(vp8_subtract_mbuv_mmx); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_encodemb_berr +#define vp8_encodemb_berr vp8_block_error_mmx + +#undef vp8_encodemb_mberr +#define vp8_encodemb_mberr vp8_mbblock_error_mmx + +#undef vp8_encodemb_mbuverr +#define vp8_encodemb_mbuverr vp8_mbuverror_mmx + +#undef vp8_encodemb_subb +#define vp8_encodemb_subb vp8_subtract_b_mmx + +#undef vp8_encodemb_submby +#define vp8_encodemb_submby vp8_subtract_mby_mmx + +#undef vp8_encodemb_submbuv +#define vp8_encodemb_submbuv vp8_subtract_mbuv_mmx + +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_berr(vp8_block_error_xmm); +extern prototype_mberr(vp8_mbblock_error_xmm); +extern prototype_mbuverr(vp8_mbuverror_xmm); + + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_encodemb_berr +#define vp8_encodemb_berr vp8_block_error_xmm + +#undef vp8_encodemb_mberr +#define vp8_encodemb_mberr vp8_mbblock_error_xmm + +#undef vp8_encodemb_mbuverr +#define vp8_encodemb_mbuverr vp8_mbuverror_xmm + +#endif +#endif + + +#endif
diff --git a/vp8/encoder/x86/encodeopt.asm b/vp8/encoder/x86/encodeopt.asm new file mode 100644 index 0000000..1940471 --- /dev/null +++ b/vp8/encoder/x86/encodeopt.asm
@@ -0,0 +1,393 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + + +;int vp8_block_error_xmm(short *coeff_ptr, short *dcoef_ptr) +global sym(vp8_block_error_xmm) +sym(vp8_block_error_xmm): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor xmm7, xmm7 + + mov rdi, arg(1) ;dcoef_ptr + movdqa xmm3, [rsi] + + movdqa xmm4, [rdi] + movdqa xmm5, [rsi+16] + + movdqa xmm6, [rdi+16] + pxor xmm1, xmm1 ; from movd xmm1, dc; dc=0 + + movdqa xmm2, xmm7 + psubw xmm5, xmm6 + + por xmm1, xmm2 + pmaddwd xmm5, xmm5 + + pcmpeqw xmm1, xmm7 + psubw xmm3, xmm4 + + pand xmm1, xmm3 + pmaddwd xmm1, xmm1 + + paddd xmm1, xmm5 + movdqa xmm0, xmm1 + + punpckldq xmm0, xmm7 + punpckhdq xmm1, xmm7 + + paddd xmm0, xmm1 + movdqa xmm1, xmm0 + + psrldq xmm0, 8 + paddd xmm0, xmm1 + + movd rax, xmm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_block_error_mmx(short *coeff_ptr, short *dcoef_ptr) +global sym(vp8_block_error_mmx) +sym(vp8_block_error_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor mm7, mm7 + + mov rdi, arg(1) ;dcoef_ptr + movq mm3, [rsi] + + movq mm4, [rdi] + movq mm5, [rsi+8] + + movq mm6, [rdi+8] + pxor mm1, mm1 ; from movd mm1, dc ; dc =0 + + movq mm2, mm7 + psubw mm5, mm6 + + por mm1, mm2 + pmaddwd mm5, mm5 + + pcmpeqw mm1, mm7 + psubw mm3, mm4 + + pand mm1, mm3 + pmaddwd mm1, mm1 + + paddd mm1, mm5 + movq mm3, [rsi+16] + + movq mm4, [rdi+16] + movq mm5, [rsi+24] + + movq mm6, [rdi+24] + psubw mm5, mm6 + + pmaddwd mm5, mm5 + psubw mm3, mm4 + + pmaddwd mm3, mm3 + paddd mm3, mm5 + + paddd mm1, mm3 + movq mm0, mm1 + + psrlq mm1, 32 + paddd mm0, mm1 + + movd rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbblock_error_mmx_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +global sym(vp8_mbblock_error_mmx_impl) +sym(vp8_mbblock_error_mmx_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor mm7, mm7 + + mov rdi, arg(1) ;dcoef_ptr + pxor mm2, mm2 + + movd mm1, dword ptr arg(2) ;dc + por mm1, mm2 + + pcmpeqw mm1, mm7 + mov rcx, 16 + +mberror_loop_mmx: + movq mm3, [rsi] + movq mm4, [rdi] + + movq mm5, [rsi+8] + movq mm6, [rdi+8] + + + psubw mm5, mm6 + pmaddwd mm5, mm5 + + psubw mm3, mm4 + pand mm3, mm1 + + pmaddwd mm3, mm3 + paddd mm2, mm5 + + paddd mm2, mm3 + movq mm3, [rsi+16] + + movq mm4, [rdi+16] + movq mm5, [rsi+24] + + movq mm6, [rdi+24] + psubw mm5, mm6 + + pmaddwd mm5, mm5 + psubw mm3, mm4 + + pmaddwd mm3, mm3 + paddd mm2, mm5 + + paddd mm2, mm3 + add rsi, 32 + + add rdi, 32 + sub rcx, 1 + + jnz mberror_loop_mmx + + movq mm0, mm2 + psrlq mm2, 32 + + paddd mm0, mm2 + movd rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbblock_error_xmm_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +global sym(vp8_mbblock_error_xmm_impl) +sym(vp8_mbblock_error_xmm_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + pxor xmm7, xmm7 + + mov rdi, arg(1) ;dcoef_ptr + pxor xmm2, xmm2 + + movd xmm1, dword ptr arg(2) ;dc + por xmm1, xmm2 + + pcmpeqw xmm1, xmm7 + mov rcx, 16 + +mberror_loop: + movdqa xmm3, [rsi] + movdqa xmm4, [rdi] + + movdqa xmm5, [rsi+16] + movdqa xmm6, [rdi+16] + + + psubw xmm5, xmm6 + pmaddwd xmm5, xmm5 + + psubw xmm3, xmm4 + pand xmm3, xmm1 + + pmaddwd xmm3, xmm3 + add rsi, 32 + + add rdi, 32 + + sub rcx, 1 + paddd xmm2, xmm5 + + paddd xmm2, xmm3 + jnz mberror_loop + + movdqa xmm0, xmm2 + punpckldq xmm0, xmm7 + + punpckhdq xmm2, xmm7 + paddd xmm0, xmm2 + + movdqa xmm1, xmm0 + psrldq xmm0, 8 + + paddd xmm0, xmm1 + movd rax, xmm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbuverror_mmx_impl(short *s_ptr, short *d_ptr); +global sym(vp8_mbuverror_mmx_impl) +sym(vp8_mbuverror_mmx_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;s_ptr + mov rdi, arg(1) ;d_ptr + + mov rcx, 16 + pxor mm7, mm7 + +mbuverror_loop_mmx: + + movq mm1, [rsi] + movq mm2, [rdi] + + psubw mm1, mm2 + pmaddwd mm1, mm1 + + + movq mm3, [rsi+8] + movq mm4, [rdi+8] + + psubw mm3, mm4 + pmaddwd mm3, mm3 + + + paddd mm7, mm1 + paddd mm7, mm3 + + + add rsi, 16 + add rdi, 16 + + dec rcx + jnz mbuverror_loop_mmx + + movq mm0, mm7 + psrlq mm7, 32 + + paddd mm0, mm7 + movd rax, mm0 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_mbuverror_xmm_impl(short *s_ptr, short *d_ptr); +global sym(vp8_mbuverror_xmm_impl) +sym(vp8_mbuverror_xmm_impl): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 2 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;s_ptr + mov rdi, arg(1) ;d_ptr + + mov rcx, 16 + pxor xmm7, xmm7 + +mbuverror_loop: + + movdqa xmm1, [rsi] + movdqa xmm2, [rdi] + + psubw xmm1, xmm2 + pmaddwd xmm1, xmm1 + + paddd xmm7, xmm1 + + add rsi, 16 + add rdi, 16 + + dec rcx + jnz mbuverror_loop + + pxor xmm0, xmm0 + movdqa xmm1, xmm7 + + movdqa xmm2, xmm1 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + paddd xmm1, xmm2 + + movdqa xmm2, xmm1 + + psrldq xmm1, 8 + paddd xmm1, xmm2 + + movd rax, xmm1 + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/fwalsh_sse2.asm b/vp8/encoder/x86/fwalsh_sse2.asm new file mode 100644 index 0000000..7d86201 --- /dev/null +++ b/vp8/encoder/x86/fwalsh_sse2.asm
@@ -0,0 +1,117 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_short_walsh4x4_sse2(short *input, short *output, int pitch) +global sym(vp8_short_walsh4x4_sse2) +sym(vp8_short_walsh4x4_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 3 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) + mov rdi, arg(1) + + movdqu xmm4, [rsi + 0] ;ip[4] ip[0] + movdqu xmm0, [rsi + 16] ;ip[12] ip[8] + + pxor xmm7, xmm7 + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; 13 12 11 10 03 02 01 00 + ; + ; 33 32 31 30 23 22 21 20 + ; + movdqa xmm3, xmm4 ; 13 12 11 10 03 02 01 00 + punpcklwd xmm4, xmm0 ; 23 03 22 02 21 01 20 00 + punpckhwd xmm3, xmm0 ; 33 13 32 12 31 11 30 10 + movdqa xmm1, xmm4 ; 23 03 22 02 21 01 20 00 + punpcklwd xmm4, xmm3 ; 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm3 ; 33 23 13 03 32 22 12 02 + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm4 ;ip[4] ip[0] + + paddw xmm4, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm3 ;d1 a1 + punpckhqdq xmm5, xmm3 ;c1 b1 + + movdqa xmm1, xmm5 ;c1 b1 + paddw xmm5, xmm4 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm4, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; 13 12 11 10 03 02 01 00 + ; + ; 33 32 31 30 23 22 21 20 + ; + movdqa xmm0, xmm5 ; 13 12 11 10 03 02 01 00 + punpcklwd xmm5, xmm4 ; 23 03 22 02 21 01 20 00 + punpckhwd xmm0, xmm4 ; 33 13 32 12 31 11 30 10 + movdqa xmm1, xmm5 ; 23 03 22 02 21 01 20 00 + punpcklwd xmm5, xmm0 ; 31 21 11 01 30 20 10 00 + punpckhwd xmm1, xmm0 ; 33 23 13 03 32 22 12 02 + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + pshufd xmm2, xmm1, 4eh ;ip[8] ip[12] + movdqa xmm3, xmm5 ;ip[4] ip[0] + + paddw xmm5, xmm2 ;ip[4]+ip[8] ip[0]+ip[12] aka b1 a1 + psubw xmm3, xmm2 ;ip[4]-ip[8] ip[0]-ip[12] aka c1 d1 + + movdqa xmm6, xmm5 + punpcklqdq xmm5, xmm3 ;d1 a1 + punpckhqdq xmm6, xmm3 ;c1 b1 + + movdqa xmm1, xmm6 ;c1 b1 + paddw xmm6, xmm5 ;dl+cl a1+b1 aka op[4] op[0] + psubw xmm5, xmm1 ;d1-c1 a1-b1 aka op[12] op[8] + + movdqa xmm0, xmm6 ;aka b2 a2 + movdqa xmm1, xmm5 ;aka d2 c2 + + pcmpgtw xmm0, xmm7 + pcmpgtw xmm1, xmm7 + + psrlw xmm0, 15 + psrlw xmm1, 15 + + paddw xmm6, xmm0 + paddw xmm5, xmm1 + + psraw xmm6, 1 + psraw xmm5, 1 + + ; a2 = a1 + b1; + ; b2 = c1 + d1; + ; c2 = a1 - b1; + ; d2 = d1 - c1; + ; a2 += (a2>0); + ; b2 += (b2>0); + ; c2 += (c2>0); + ; d2 += (d2>0); + ; op[0] = (a2)>>1; + ; op[4] = (b2)>>1; + ; op[8] = (c2)>>1; + ; op[12]= (d2)>>1; + + movdqu [rdi + 0], xmm6 + movdqu [rdi + 16], xmm5 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/mcomp_x86.h b/vp8/encoder/x86/mcomp_x86.h new file mode 100644 index 0000000..5661491 --- /dev/null +++ b/vp8/encoder/x86/mcomp_x86.h
@@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef MCOMP_X86_H +#define MCOMP_X86_H + +#if HAVE_SSE3 +#if !CONFIG_RUNTIME_CPU_DETECT + +#undef vp8_search_full_search +#define vp8_search_full_search vp8_full_search_sadx3 + +#undef vp8_search_diamond_search +#define vp8_search_diamond_search vp8_diamond_search_sadx4 + +#endif +#endif + +#endif +
diff --git a/vp8/encoder/x86/preproc_mmx.c b/vp8/encoder/x86/preproc_mmx.c new file mode 100644 index 0000000..69617ca --- /dev/null +++ b/vp8/encoder/x86/preproc_mmx.c
@@ -0,0 +1,297 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "memory.h" +#include "preproc.h" +#include "pragmas.h" + +/**************************************************************************** +* Macros +****************************************************************************/ +#define FRAMECOUNT 7 +#define ROUNDUP32(X) ( ( ( (unsigned long) X ) + 31 )&( 0xFFFFFFE0 ) ) + +/**************************************************************************** +* Imports +****************************************************************************/ +extern void vpx_get_processor_flags(int *mmx_enabled, int *xmm_enabled, int *wmt_enabled); + +/**************************************************************************** +* Exported Global Variables +****************************************************************************/ +void (*temp_filter)(pre_proc_instance *ppi, unsigned char *s, unsigned char *d, int bytes, int strength); + +/**************************************************************************** + * + * ROUTINE : temp_filter_wmt + * + * INPUTS : pre_proc_instance *ppi : Pointer to pre-processor instance. + * unsigned char *s : Pointer to source frame. + * unsigned char *d : Pointer to destination frame. + * int bytes : Number of bytes to filter. + * int strength : Strength of filter to apply. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs a closesness adjusted temporarl blur + * + * SPECIAL NOTES : Destination frame can be same as source frame. + * + ****************************************************************************/ +void temp_filter_wmt +( + pre_proc_instance *ppi, + unsigned char *s, + unsigned char *d, + int bytes, + int strength +) +{ + int byte = 0; + unsigned char *frameptr = ppi->frame_buffer; + + __declspec(align(16)) unsigned short threes[] = { 3, 3, 3, 3, 3, 3, 3, 3}; + __declspec(align(16)) unsigned short sixteens[] = {16, 16, 16, 16, 16, 16, 16, 16}; + + if (ppi->frame == 0) + { + do + { + int i; + int frame = 0; + + do + { + for (i = 0; i < 8; i++) + { + *frameptr = s[byte+i]; + ++frameptr; + } + + ++frame; + } + while (frame < FRAMECOUNT); + + for (i = 0; i < 8; i++) + d[byte+i] = s[byte+i]; + + byte += 8; + + } + while (byte < bytes); + } + else + { + int i; + int offset2 = (ppi->frame % FRAMECOUNT); + + do + { + __declspec(align(16)) unsigned short counts[8]; + __declspec(align(16)) unsigned short sums[8]; + __asm + { + mov eax, offset2 + mov edi, s // source pixels + pxor xmm1, xmm1 // accumulator + + pxor xmm7, xmm7 + + mov esi, frameptr // accumulator + pxor xmm2, xmm2 // count + + movq xmm3, QWORD PTR [edi] + + movq QWORD PTR [esi+8*eax], xmm3 + + punpcklbw xmm3, xmm2 // xmm3 source pixels + mov ecx, FRAMECOUNT + + next_frame: + movq xmm4, QWORD PTR [esi] // get frame buffer values + punpcklbw xmm4, xmm7 // xmm4 frame buffer pixels + movdqa xmm6, xmm4 // save the pixel values + psubsw xmm4, xmm3 // subtracted pixel values + pmullw xmm4, xmm4 // square xmm4 + movd xmm5, strength + psrlw xmm4, xmm5 // should be strength + pmullw xmm4, threes // 3 * modifier + movdqa xmm5, sixteens // 16s + psubusw xmm5, xmm4 // 16 - modifiers + movdqa xmm4, xmm5 // save the modifiers + pmullw xmm4, xmm6 // multiplier values + paddusw xmm1, xmm4 // accumulator + paddusw xmm2, xmm5 // count + add esi, 8 // next frame + dec ecx // next set of eight pixels + jnz next_frame + + movdqa counts, xmm2 + psrlw xmm2, 1 // divide count by 2 for rounding + paddusw xmm1, xmm2 // rounding added in + + mov frameptr, esi + + movdqa sums, xmm1 + } + + for (i = 0; i < 8; i++) + { + int blurvalue = sums[i] * ppi->fixed_divide[counts[i]]; + blurvalue >>= 16; + d[i] = blurvalue; + } + + s += 8; + d += 8; + byte += 8; + } + while (byte < bytes); + } + + ++ppi->frame; + __asm emms +} + +/**************************************************************************** + * + * ROUTINE : temp_filter_mmx + * + * INPUTS : pre_proc_instance *ppi : Pointer to pre-processor instance. + * unsigned char *s : Pointer to source frame. + * unsigned char *d : Pointer to destination frame. + * int bytes : Number of bytes to filter. + * int strength : Strength of filter to apply. + * + * OUTPUTS : None. + * + * RETURNS : void + * + * FUNCTION : Performs a closesness adjusted temporarl blur + * + * SPECIAL NOTES : Destination frame can be same as source frame. + * + ****************************************************************************/ +void temp_filter_mmx +( + pre_proc_instance *ppi, + unsigned char *s, + unsigned char *d, + int bytes, + int strength +) +{ + int byte = 0; + unsigned char *frameptr = ppi->frame_buffer; + + __declspec(align(16)) unsigned short threes[] = { 3, 3, 3, 3}; + __declspec(align(16)) unsigned short sixteens[] = {16, 16, 16, 16}; + + if (ppi->frame == 0) + { + do + { + int i; + int frame = 0; + + do + { + for (i = 0; i < 4; i++) + { + *frameptr = s[byte+i]; + ++frameptr; + } + + ++frame; + } + while (frame < FRAMECOUNT); + + for (i = 0; i < 4; i++) + d[byte+i] = s[byte+i]; + + byte += 4; + + } + while (byte < bytes); + } + else + { + int i; + int offset2 = (ppi->frame % FRAMECOUNT); + + do + { + __declspec(align(16)) unsigned short counts[8]; + __declspec(align(16)) unsigned short sums[8]; + __asm + { + + mov eax, offset2 + mov edi, s // source pixels + pxor mm1, mm1 // accumulator + pxor mm7, mm7 + + mov esi, frameptr // accumulator + pxor mm2, mm2 // count + + movd mm3, DWORD PTR [edi] + movd DWORD PTR [esi+4*eax], mm3 + + punpcklbw mm3, mm2 // mm3 source pixels + mov ecx, FRAMECOUNT + + next_frame: + movd mm4, DWORD PTR [esi] // get frame buffer values + punpcklbw mm4, mm7 // mm4 frame buffer pixels + movq mm6, mm4 // save the pixel values + psubsw mm4, mm3 // subtracted pixel values + pmullw mm4, mm4 // square mm4 + movd mm5, strength + psrlw mm4, mm5 // should be strength + pmullw mm4, threes // 3 * modifier + movq mm5, sixteens // 16s + psubusw mm5, mm4 // 16 - modifiers + movq mm4, mm5 // save the modifiers + pmullw mm4, mm6 // multiplier values + paddusw mm1, mm4 // accumulator + paddusw mm2, mm5 // count + add esi, 4 // next frame + dec ecx // next set of eight pixels + jnz next_frame + + movq counts, mm2 + psrlw mm2, 1 // divide count by 2 for rounding + paddusw mm1, mm2 // rounding added in + + mov frameptr, esi + + movq sums, mm1 + + } + + for (i = 0; i < 4; i++) + { + int blurvalue = sums[i] * ppi->fixed_divide[counts[i]]; + blurvalue >>= 16; + d[i] = blurvalue; + } + + s += 4; + d += 4; + byte += 4; + } + while (byte < bytes); + } + + ++ppi->frame; + __asm emms +}
diff --git a/vp8/encoder/x86/quantize_mmx.asm b/vp8/encoder/x86/quantize_mmx.asm new file mode 100644 index 0000000..847fc6e --- /dev/null +++ b/vp8/encoder/x86/quantize_mmx.asm
@@ -0,0 +1,438 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;int vp8_fast_quantize_b_impl_mmx(short *coeff_ptr, short *zbin_ptr, +; short *qcoeff_ptr,short *dequant_ptr, +; short *scan_mask, short *round_ptr, +; short *quant_ptr, short *dqcoeff_ptr); +global sym(vp8_fast_quantize_b_impl_mmx) +sym(vp8_fast_quantize_b_impl_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + movq mm0, [rsi] + + mov rax, arg(1) ;zbin_ptr + movq mm1, [rax] + + movq mm3, mm0 + psraw mm0, 15 + + pxor mm3, mm0 + psubw mm3, mm0 ; abs + + movq mm2, mm3 + pcmpgtw mm1, mm2 + + pandn mm1, mm2 + movq mm3, mm1 + + mov rdx, arg(6) ;quant_ptr + movq mm1, [rdx] + + mov rcx, arg(5) ;round_ptr + movq mm2, [rcx] + + paddw mm3, mm2 + pmulhuw mm3, mm1 + + pxor mm3, mm0 + psubw mm3, mm0 ;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + movq mm0, mm3 + + movq [rdi], mm3 + + mov rax, arg(3) ;dequant_ptr + movq mm2, [rax] + + pmullw mm3, mm2 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax], mm3 + + ; next 8 + movq mm4, [rsi+8] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+8] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+8] + movq mm6, [rcx+8] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+8], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+8] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+8], mm7 + + + ; next 8 + movq mm4, [rsi+16] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+16] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+16] + movq mm6, [rcx+16] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+16], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+16] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+16], mm7 + + + ; next 8 + movq mm4, [rsi+24] + + mov rax, arg(1) ;zbin_ptr + movq mm5, [rax+24] + + movq mm7, mm4 + psraw mm4, 15 + + pxor mm7, mm4 + psubw mm7, mm4 ; abs + + movq mm6, mm7 + pcmpgtw mm5, mm6 + + pandn mm5, mm6 + movq mm7, mm5 + + movq mm5, [rdx+24] + movq mm6, [rcx+24] + + paddw mm7, mm6 + pmulhuw mm7, mm5 + + pxor mm7, mm4 + psubw mm7, mm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movq mm1, mm7 + movq [rdi+24], mm7 + + mov rax, arg(3) ;dequant_ptr + movq mm6, [rax+24] + + pmullw mm7, mm6 + mov rax, arg(7) ;dqcoeff_ptr + + movq [rax+24], mm7 + + + + mov rdi, arg(4) ;scan_mask + mov rsi, arg(2) ;qcoeff_ptr + + pxor mm5, mm5 + pxor mm7, mm7 + + movq mm0, [rsi] + movq mm1, [rsi+8] + + movq mm2, [rdi] + movq mm3, [rdi+8]; + + pcmpeqw mm0, mm7 + pcmpeqw mm1, mm7 + + pcmpeqw mm6, mm6 + pxor mm0, mm6 + + pxor mm1, mm6 + psrlw mm0, 15 + + psrlw mm1, 15 + pmaddwd mm0, mm2 + + pmaddwd mm1, mm3 + movq mm5, mm0 + + paddd mm5, mm1 + + movq mm0, [rsi+16] + movq mm1, [rsi+24] + + movq mm2, [rdi+16] + movq mm3, [rdi+24]; + + pcmpeqw mm0, mm7 + pcmpeqw mm1, mm7 + + pcmpeqw mm6, mm6 + pxor mm0, mm6 + + pxor mm1, mm6 + psrlw mm0, 15 + + psrlw mm1, 15 + pmaddwd mm0, mm2 + + pmaddwd mm1, mm3 + paddd mm5, mm0 + + paddd mm5, mm1 + movq mm0, mm5 + + psrlq mm5, 32 + paddd mm0, mm5 + + ; eob adjustment begins here + movd rcx, mm0 + and rcx, 0xffff + + xor rdx, rdx + sub rdx, rcx ; rdx=-rcx + + bsr rax, rcx + inc rax + + sar rdx, 31 + and rax, rdx + ; Substitute the sse assembly for the old mmx mixed assembly/C. The + ; following is kept as reference + ; movd rcx, mm0 + ; bsr rax, rcx + ; + ; mov eob, rax + ; mov eee, rcx + ; + ;if(eee==0) + ;{ + ; eob=-1; + ;} + ;else if(eee<0) + ;{ + ; eob=15; + ;} + ;d->eob = eob+1; + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;int vp8_fast_quantize_b_impl_sse(short *coeff_ptr, short *zbin_ptr, +; short *qcoeff_ptr,short *dequant_ptr, +; short *scan_mask, short *round_ptr, +; short *quant_ptr, short *dqcoeff_ptr); +global sym(vp8_fast_quantize_b_impl_sse) +sym(vp8_fast_quantize_b_impl_sse): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;coeff_ptr + movdqa xmm0, [rsi] + + mov rax, arg(1) ;zbin_ptr + movdqa xmm1, [rax] + + movdqa xmm3, xmm0 + psraw xmm0, 15 + + pxor xmm3, xmm0 + psubw xmm3, xmm0 ; abs + + movdqa xmm2, xmm3 + pcmpgtw xmm1, xmm2 + + pandn xmm1, xmm2 + movdqa xmm3, xmm1 + + mov rdx, arg(6) ; quant_ptr + movdqa xmm1, [rdx] + + mov rcx, arg(5) ; round_ptr + movdqa xmm2, [rcx] + + paddw xmm3, xmm2 + pmulhuw xmm3, xmm1 + + pxor xmm3, xmm0 + psubw xmm3, xmm0 ;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + movdqa xmm0, xmm3 + + movdqa [rdi], xmm3 + + mov rax, arg(3) ;dequant_ptr + movdqa xmm2, [rax] + + pmullw xmm3, xmm2 + mov rax, arg(7) ;dqcoeff_ptr + + movdqa [rax], xmm3 + + ; next 8 + movdqa xmm4, [rsi+16] + + mov rax, arg(1) ;zbin_ptr + movdqa xmm5, [rax+16] + + movdqa xmm7, xmm4 + psraw xmm4, 15 + + pxor xmm7, xmm4 + psubw xmm7, xmm4 ; abs + + movdqa xmm6, xmm7 + pcmpgtw xmm5, xmm6 + + pandn xmm5, xmm6 + movdqa xmm7, xmm5 + + movdqa xmm5, [rdx+16] + movdqa xmm6, [rcx+16] + + + paddw xmm7, xmm6 + pmulhuw xmm7, xmm5 + + pxor xmm7, xmm4 + psubw xmm7, xmm4;gain the sign back + + mov rdi, arg(2) ;qcoeff_ptr + + movdqa xmm1, xmm7 + movdqa [rdi+16], xmm7 + + mov rax, arg(3) ;dequant_ptr + movdqa xmm6, [rax+16] + + pmullw xmm7, xmm6 + mov rax, arg(7) ;dqcoeff_ptr + + movdqa [rax+16], xmm7 + mov rdi, arg(4) ;scan_mask + + pxor xmm7, xmm7 + movdqa xmm2, [rdi] + + movdqa xmm3, [rdi+16]; + pcmpeqw xmm0, xmm7 + + pcmpeqw xmm1, xmm7 + pcmpeqw xmm6, xmm6 + + pxor xmm0, xmm6 + pxor xmm1, xmm6 + + psrlw xmm0, 15 + psrlw xmm1, 15 + + pmaddwd xmm0, xmm2 + pmaddwd xmm1, xmm3 + + movq xmm2, xmm0 + movq xmm3, xmm1 + + psrldq xmm0, 8 + psrldq xmm1, 8 + + paddd xmm0, xmm1 + paddd xmm2, xmm3 + + paddd xmm0, xmm2 + movq xmm1, xmm0 + + psrldq xmm0, 4 + paddd xmm1, xmm0 + + movd rcx, xmm1 + and rcx, 0xffff + + xor rdx, rdx + sub rdx, rcx + + bsr rax, rcx + inc rax + + sar rdx, 31 + and rax, rdx + + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/sad_mmx.asm b/vp8/encoder/x86/sad_mmx.asm new file mode 100644 index 0000000..a825698 --- /dev/null +++ b/vp8/encoder/x86/sad_mmx.asm
@@ -0,0 +1,428 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +global sym(vp8_sad16x16_mmx) +global sym(vp8_sad8x16_mmx) +global sym(vp8_sad8x8_mmx) +global sym(vp8_sad4x4_mmx) +global sym(vp8_sad16x8_mmx) + +%idefine QWORD + +;unsigned int vp8_sad16x16_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad16x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +x16x16sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm2, QWORD PTR [rsi+8] + + movq mm1, QWORD PTR [rdi] + movq mm3, QWORD PTR [rdi+8] + + movq mm4, mm0 + movq mm5, mm2 + + psubusb mm0, mm1 + psubusb mm1, mm4 + + psubusb mm2, mm3 + psubusb mm3, mm5 + + por mm0, mm1 + por mm2, mm3 + + movq mm1, mm0 + movq mm3, mm2 + + punpcklbw mm0, mm6 + punpcklbw mm2, mm6 + + punpckhbw mm1, mm6 + punpckhbw mm3, mm6 + + paddw mm0, mm2 + paddw mm1, mm3 + + + lea rsi, [rsi+rax] + add rdi, rdx + + paddw mm7, mm0 + paddw mm7, mm1 + + cmp rsi, rcx + jne x16x16sad_mmx_loop + + + movq mm0, mm7 + + punpcklwd mm0, mm6 + punpckhwd mm7, mm6 + + paddw mm0, mm7 + movq mm7, mm0 + + + psrlq mm0, 32 + paddw mm7, mm0 + + movd rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x16_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad8x16_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +x8x16sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + punpcklbw mm0, mm6 + + punpckhbw mm2, mm6 + lea rsi, [rsi+rax] + + add rdi, rdx + paddw mm7, mm0 + + paddw mm7, mm2 + cmp rsi, rcx + + jne x8x16sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movd rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x8_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad8x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +x8x8sad_mmx_loop: + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + punpcklbw mm0, mm6 + + punpckhbw mm2, mm6 + paddw mm0, mm2 + + lea rsi, [rsi+rax] + add rdi, rdx + + paddw mm7, mm0 + cmp rsi, rcx + + jne x8x8sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movd rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad4x4_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad4x4_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + movd mm0, QWORD PTR [rsi] + movd mm1, QWORD PTR [rdi] + + movd mm2, QWORD PTR [rsi+rax] + movd mm3, QWORD PTR [rdi+rdx] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movq mm2, mm0 + psubusb mm0, mm1 + + psubusb mm1, mm2 + por mm0, mm1 + + movq mm2, mm0 + pxor mm3, mm3 + + punpcklbw mm0, mm3 + punpckhbw mm2, mm3 + + paddw mm0, mm2 + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + movd mm4, QWORD PTR [rsi] + movd mm5, QWORD PTR [rdi] + + movd mm6, QWORD PTR [rsi+rax] + movd mm7, QWORD PTR [rdi+rdx] + + punpcklbw mm4, mm6 + punpcklbw mm5, mm7 + + movq mm6, mm4 + psubusb mm4, mm5 + + psubusb mm5, mm6 + por mm4, mm5 + + movq mm5, mm4 + punpcklbw mm4, mm3 + + punpckhbw mm5, mm3 + paddw mm4, mm5 + + paddw mm0, mm4 + movq mm1, mm0 + + punpcklwd mm0, mm3 + punpckhwd mm1, mm3 + + paddw mm0, mm1 + movq mm1, mm0 + + psrlq mm0, 32 + paddw mm0, mm1 + + movd rax, mm0 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad16x8_mmx( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +sym(vp8_sad16x8_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + pxor mm7, mm7 + + pxor mm6, mm6 + +x16x8sad_mmx_loop: + + movq mm0, [rsi] + movq mm1, [rdi] + + movq mm2, [rsi+8] + movq mm3, [rdi+8] + + movq mm4, mm0 + movq mm5, mm2 + + psubusb mm0, mm1 + psubusb mm1, mm4 + + psubusb mm2, mm3 + psubusb mm3, mm5 + + por mm0, mm1 + por mm2, mm3 + + movq mm1, mm0 + movq mm3, mm2 + + punpcklbw mm0, mm6 + punpckhbw mm1, mm6 + + punpcklbw mm2, mm6 + punpckhbw mm3, mm6 + + + paddw mm0, mm2 + paddw mm1, mm3 + + paddw mm0, mm1 + lea rsi, [rsi+rax] + + add rdi, rdx + paddw mm7, mm0 + + cmp rsi, rcx + jne x16x8sad_mmx_loop + + movq mm0, mm7 + punpcklwd mm0, mm6 + + punpckhwd mm7, mm6 + paddw mm0, mm7 + + movq mm7, mm0 + psrlq mm0, 32 + + paddw mm7, mm0 + movd rax, mm7 + + pop rdi + pop rsi + mov rsp, rbp + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/sad_sse2.asm b/vp8/encoder/x86/sad_sse2.asm new file mode 100644 index 0000000..53240bb --- /dev/null +++ b/vp8/encoder/x86/sad_sse2.asm
@@ -0,0 +1,329 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%idefine QWORD + +;unsigned int vp8_sad16x16_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad16x16_wmt) +sym(vp8_sad16x16_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rax*8] + + lea rcx, [rcx+rax*8] + pxor xmm7, xmm7 + +x16x16sad_wmt_loop: + + movq xmm0, QWORD PTR [rsi] + movq xmm2, QWORD PTR [rsi+8] + + movq xmm1, QWORD PTR [rdi] + movq xmm3, QWORD PTR [rdi+8] + + movq xmm4, QWORD PTR [rsi+rax] + movq xmm5, QWORD PTR [rdi+rdx] + + + punpcklbw xmm0, xmm2 + punpcklbw xmm1, xmm3 + + psadbw xmm0, xmm1 + movq xmm6, QWORD PTR [rsi+rax+8] + + movq xmm3, QWORD PTR [rdi+rdx+8] + lea rsi, [rsi+rax*2] + + lea rdi, [rdi+rdx*2] + punpcklbw xmm4, xmm6 + + punpcklbw xmm5, xmm3 + psadbw xmm4, xmm5 + + paddw xmm7, xmm0 + paddw xmm7, xmm4 + + cmp rsi, rcx + jne x16x16sad_wmt_loop + + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd rax, xmm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_sad8x16_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int max_err) +global sym(vp8_sad8x16_wmt) +sym(vp8_sad8x16_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + + lea rcx, [rcx+rbx*8] + pxor mm7, mm7 + +x8x16sad_wmt_loop: + + movd rax, mm7 + cmp rax, arg(4) + jg x8x16sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + movq mm2, QWORD PTR [rsi+rbx] + movq mm3, QWORD PTR [rdi+rdx] + + psadbw mm0, mm1 + psadbw mm2, mm3 + + lea rsi, [rsi+rbx*2] + lea rdi, [rdi+rdx*2] + + paddw mm7, mm0 + paddw mm7, mm2 + + cmp rsi, rcx + jne x8x16sad_wmt_loop + + movd rax, mm7 + +x8x16sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad8x8_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad8x8_wmt) +sym(vp8_sad8x8_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + pxor mm7, mm7 + +x8x8sad_wmt_loop: + + movd rax, mm7 + cmp rax, arg(4) + jg x8x8sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm1, QWORD PTR [rdi] + + psadbw mm0, mm1 + lea rsi, [rsi+rbx] + + add rdi, rdx + paddw mm7, mm0 + + cmp rsi, rcx + jne x8x8sad_wmt_loop + + movd rax, mm7 +x8x8sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_sad4x4_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad4x4_wmt) +sym(vp8_sad4x4_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + movd mm0, QWORD PTR [rsi] + movd mm1, QWORD PTR [rdi] + + movd mm2, QWORD PTR [rsi+rax] + movd mm3, QWORD PTR [rdi+rdx] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + psadbw mm0, mm1 + lea rsi, [rsi+rax*2] + + lea rdi, [rdi+rdx*2] + movd mm4, QWORD PTR [rsi] + + movd mm5, QWORD PTR [rdi] + movd mm6, QWORD PTR [rsi+rax] + + movd mm7, QWORD PTR [rdi+rdx] + punpcklbw mm4, mm6 + + punpcklbw mm5, mm7 + psadbw mm4, mm5 + + paddw mm0, mm4 + movd rax, mm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_sad16x8_wmt( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride) +global sym(vp8_sad16x8_wmt) +sym(vp8_sad16x8_wmt): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + pxor mm7, mm7 + +x16x8sad_wmt_loop: + + movd rax, mm7 + cmp rax, arg(4) + jg x16x8sad_wmt_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm2, QWORD PTR [rsi+8] + + movq mm1, QWORD PTR [rdi] + movq mm3, QWORD PTR [rdi+8] + + movq mm4, QWORD PTR [rsi+rbx] + movq mm5, QWORD PTR [rdi+rdx] + + psadbw mm0, mm1 + psadbw mm2, mm3 + + movq mm1, QWORD PTR [rsi+rbx+8] + movq mm3, QWORD PTR [rdi+rdx+8] + + psadbw mm4, mm5 + psadbw mm1, mm3 + + lea rsi, [rsi+rbx*2] + lea rdi, [rdi+rdx*2] + + paddw mm0, mm2 + paddw mm4, mm1 + + paddw mm7, mm0 + paddw mm7, mm4 + + cmp rsi, rcx + jne x16x8sad_wmt_loop + + movd rax, mm7 + +x16x8sad_wmt_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/sad_sse3.asm b/vp8/encoder/x86/sad_sse3.asm new file mode 100644 index 0000000..38cc029 --- /dev/null +++ b/vp8/encoder/x86/sad_sse3.asm
@@ -0,0 +1,939 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%idefine QWORD + +%macro PROCESS_16X2X3 1 +%if %1 + movdqa xmm0, [rsi] + lddqu xmm5, [rdi] + lddqu xmm6, [rdi+1] + lddqu xmm7, [rdi+2] + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, [rsi] + lddqu xmm1, [rdi] + lddqu xmm2, [rdi+1] + lddqu xmm3, [rdi+2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, QWORD PTR [rsi+rax] + lddqu xmm1, QWORD PTR [rdi+rdx] + lddqu xmm2, QWORD PTR [rdi+rdx+1] + lddqu xmm3, QWORD PTR [rdi+rdx+2] + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_8X2X3 1 +%if %1 + movq mm0, [rsi] + movq mm5, [rdi] + movq mm6, [rdi+1] + movq mm7, [rdi+2] + + psadbw mm5, mm0 + psadbw mm6, mm0 + psadbw mm7, mm0 +%else + movq mm0, [rsi] + movq mm1, [rdi] + movq mm2, [rdi+1] + movq mm3, [rdi+2] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm5, mm1 + paddw mm6, mm2 + paddw mm7, mm3 +%endif + movq mm0, QWORD PTR [rsi+rax] + movq mm1, QWORD PTR [rdi+rdx] + movq mm2, QWORD PTR [rdi+rdx+1] + movq mm3, QWORD PTR [rdi+rdx+2] + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm5, mm1 + paddw mm6, mm2 + paddw mm7, mm3 +%endmacro + +%macro LOAD_X4_ADDRESSES 5 + mov %2, [%1+REG_SZ_BYTES*0] + mov %3, [%1+REG_SZ_BYTES*1] + + mov %4, [%1+REG_SZ_BYTES*2] + mov %5, [%1+REG_SZ_BYTES*3] +%endmacro + +%macro PROCESS_16X2X4 1 +%if %1 + movdqa xmm0, [rsi] + lddqu xmm4, [rcx] + lddqu xmm5, [rdx] + lddqu xmm6, [rbx] + lddqu xmm7, [rdi] + + psadbw xmm4, xmm0 + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, [rsi] + lddqu xmm1, [rcx] + lddqu xmm2, [rdx] + lddqu xmm3, [rbx] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm4, xmm1 + lddqu xmm1, [rdi] + paddw xmm5, xmm2 + paddw xmm6, xmm3 + + psadbw xmm1, xmm0 + paddw xmm7, xmm1 +%endif + movdqa xmm0, QWORD PTR [rsi+rax] + lddqu xmm1, QWORD PTR [rcx+rbp] + lddqu xmm2, QWORD PTR [rdx+rbp] + lddqu xmm3, QWORD PTR [rbx+rbp] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm4, xmm1 + lddqu xmm1, QWORD PTR [rdi+rbp] + paddw xmm5, xmm2 + paddw xmm6, xmm3 + + lea rsi, [rsi+rax*2] + lea rcx, [rcx+rbp*2] + + lea rdx, [rdx+rbp*2] + lea rbx, [rbx+rbp*2] + + lea rdi, [rdi+rbp*2] + + psadbw xmm1, xmm0 + paddw xmm7, xmm1 + +%endmacro + +%macro PROCESS_8X2X4 1 +%if %1 + movq mm0, [rsi] + movq mm4, [rcx] + movq mm5, [rdx] + movq mm6, [rbx] + movq mm7, [rdi] + + psadbw mm4, mm0 + psadbw mm5, mm0 + psadbw mm6, mm0 + psadbw mm7, mm0 +%else + movq mm0, [rsi] + movq mm1, [rcx] + movq mm2, [rdx] + movq mm3, [rbx] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm4, mm1 + movq mm1, [rdi] + paddw mm5, mm2 + paddw mm6, mm3 + + psadbw mm1, mm0 + paddw mm7, mm1 +%endif + movq mm0, QWORD PTR [rsi+rax] + movq mm1, QWORD PTR [rcx+rbp] + movq mm2, QWORD PTR [rdx+rbp] + movq mm3, QWORD PTR [rbx+rbp] + + psadbw mm1, mm0 + psadbw mm2, mm0 + psadbw mm3, mm0 + + paddw mm4, mm1 + movq mm1, QWORD PTR [rdi+rbp] + paddw mm5, mm2 + paddw mm6, mm3 + + lea rsi, [rsi+rax*2] + lea rcx, [rcx+rbp*2] + + lea rdx, [rdx+rbp*2] + lea rbx, [rbx+rbp*2] + + lea rdi, [rdi+rbp*2] + + psadbw mm1, mm0 + paddw mm7, mm1 + +%endmacro + +;void int vp8_sad16x16x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x3_sse3) +sym(vp8_sad16x16x3_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad16x8x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x3_sse3) +sym(vp8_sad16x8x3_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad8x16x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x16x3_sse3) +sym(vp8_sad8x16x3_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_8X2X3 1 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + + mov rdi, arg(4) ;Results + + movd [rdi], mm5 + movd [rdi+4], mm6 + movd [rdi+8], mm7 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad8x8x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x8x3_sse3) +sym(vp8_sad8x8x3_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + PROCESS_8X2X3 1 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + PROCESS_8X2X3 0 + + mov rdi, arg(4) ;Results + + movd [rdi], mm5 + movd [rdi+4], mm6 + movd [rdi+8], mm7 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad4x4x3_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad4x4x3_sse3) +sym(vp8_sad4x4x3_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + movd mm0, QWORD PTR [rsi] + movd mm1, QWORD PTR [rdi] + + movd mm2, QWORD PTR [rsi+rax] + movd mm3, QWORD PTR [rdi+rdx] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movd mm4, QWORD PTR [rdi+1] + movd mm5, QWORD PTR [rdi+2] + + movd mm2, QWORD PTR [rdi+rdx+1] + movd mm3, QWORD PTR [rdi+rdx+2] + + psadbw mm1, mm0 + + punpcklbw mm4, mm2 + punpcklbw mm5, mm3 + + psadbw mm4, mm0 + psadbw mm5, mm0 + + + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + movd mm0, QWORD PTR [rsi] + movd mm2, QWORD PTR [rdi] + + movd mm3, QWORD PTR [rsi+rax] + movd mm6, QWORD PTR [rdi+rdx] + + punpcklbw mm0, mm3 + punpcklbw mm2, mm6 + + movd mm3, QWORD PTR [rdi+1] + movd mm7, QWORD PTR [rdi+2] + + psadbw mm2, mm0 + + paddw mm1, mm2 + + movd mm2, QWORD PTR [rdi+rdx+1] + movd mm6, QWORD PTR [rdi+rdx+2] + + punpcklbw mm3, mm2 + punpcklbw mm7, mm6 + + psadbw mm3, mm0 + psadbw mm7, mm0 + + paddw mm3, mm4 + paddw mm7, mm5 + + mov rdi, arg(4) ;Results + movd [rdi], mm1 + + movd [rdi+4], mm3 + movd [rdi+8], mm7 + + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_sad16x16_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int max_err) +;%define lddqu movdqu +global sym(vp8_sad16x16_sse3) +sym(vp8_sad16x16_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rbx + push rsi + push rdi + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + lea rcx, [rsi+rbx*8] + + lea rcx, [rcx+rbx*8] + pxor mm7, mm7 + +vp8_sad16x16_sse3_loop: + + movd rax, mm7 + cmp rax, arg(4) + jg vp8_sad16x16_early_exit + + movq mm0, QWORD PTR [rsi] + movq mm2, QWORD PTR [rsi+8] + + movq mm1, QWORD PTR [rdi] + movq mm3, QWORD PTR [rdi+8] + + movq mm4, QWORD PTR [rsi+rbx] + movq mm5, QWORD PTR [rdi+rdx] + + psadbw mm0, mm1 + psadbw mm2, mm3 + + movq mm1, QWORD PTR [rsi+rbx+8] + movq mm3, QWORD PTR [rdi+rdx+8] + + psadbw mm4, mm5 + psadbw mm1, mm3 + + lea rsi, [rsi+rbx*2] + lea rdi, [rdi+rdx*2] + + paddw mm0, mm2 + paddw mm4, mm1 + + paddw mm7, mm0 + paddw mm7, mm4 + + cmp rsi, rcx + jne vp8_sad16x16_sse3_loop + + movd rax, mm7 + +vp8_sad16x16_early_exit: + + ; begin epilog + pop rdi + pop rsi + pop rbx + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_sad16x16x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr_base, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x4d_sse3) +sym(vp8_sad16x16x4d_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rbx + ; end prolog + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ;src_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rbp, dword ptr arg(3) ;ref_stride + + xchg rbx, rax + + PROCESS_16X2X4 1 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + + pop rbp + mov rdi, arg(4) ;Results + + movq xmm0, xmm4 + psrldq xmm4, 8 + + paddw xmm0, xmm4 + movd [rdi], xmm0 +;- + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+8], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+12], xmm0 + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_sad16x8x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr_base, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x4d_sse3) +sym(vp8_sad16x8x4d_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rbx + ; end prolog + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ;src_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rbp, dword ptr arg(3) ;ref_stride + + xchg rbx, rax + + PROCESS_16X2X4 1 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + PROCESS_16X2X4 0 + + pop rbp + mov rdi, arg(4) ;Results + + movq xmm0, xmm4 + psrldq xmm4, 8 + + paddw xmm0, xmm4 + movd [rdi], xmm0 +;- + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+8], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+12], xmm0 + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad8x16x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x16x4d_sse3) +sym(vp8_sad8x16x4d_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rbx + ; end prolog + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ;src_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rbp, dword ptr arg(3) ;ref_stride + + xchg rbx, rax + + PROCESS_8X2X4 1 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + + pop rbp + mov rdi, arg(4) ;Results + + movd [rdi], mm4 + movd [rdi+4], mm5 + movd [rdi+8], mm6 + movd [rdi+12], mm7 + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad8x8x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad8x8x4d_sse3) +sym(vp8_sad8x8x4d_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rbx + ; end prolog + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ;src_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rbp, dword ptr arg(3) ;ref_stride + + xchg rbx, rax + + PROCESS_8X2X4 1 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + PROCESS_8X2X4 0 + + pop rbp + mov rdi, arg(4) ;Results + + movd [rdi], mm4 + movd [rdi+4], mm5 + movd [rdi+8], mm6 + movd [rdi+12], mm7 + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad4x4x4d_sse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad4x4x4d_sse3) +sym(vp8_sad4x4x4d_sse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rbx + ; end prolog + + push rbp + mov rdi, arg(2) ; ref_ptr_base + + LOAD_X4_ADDRESSES rdi, rcx, rdx, rax, rdi + + mov rsi, arg(0) ;src_ptr + + movsxd rbx, dword ptr arg(1) ;src_stride + movsxd rbp, dword ptr arg(3) ;ref_stride + + xchg rbx, rax + + movd mm0, QWORD PTR [rsi] + movd mm1, QWORD PTR [rcx] + + movd mm2, QWORD PTR [rsi+rax] + movd mm3, QWORD PTR [rcx+rbp] + + punpcklbw mm0, mm2 + punpcklbw mm1, mm3 + + movd mm4, QWORD PTR [rdx] + movd mm5, QWORD PTR [rbx] + + movd mm6, QWORD PTR [rdi] + movd mm2, QWORD PTR [rdx+rbp] + + movd mm3, QWORD PTR [rbx+rbp] + movd mm7, QWORD PTR [rdi+rbp] + + psadbw mm1, mm0 + + punpcklbw mm4, mm2 + punpcklbw mm5, mm3 + + punpcklbw mm6, mm7 + psadbw mm4, mm0 + + psadbw mm5, mm0 + psadbw mm6, mm0 + + + + lea rsi, [rsi+rax*2] + lea rcx, [rcx+rbp*2] + + lea rdx, [rdx+rbp*2] + lea rbx, [rbx+rbp*2] + + lea rdi, [rdi+rbp*2] + + movd mm0, QWORD PTR [rsi] + movd mm2, QWORD PTR [rcx] + + movd mm3, QWORD PTR [rsi+rax] + movd mm7, QWORD PTR [rcx+rbp] + + punpcklbw mm0, mm3 + punpcklbw mm2, mm7 + + movd mm3, QWORD PTR [rdx] + movd mm7, QWORD PTR [rbx] + + psadbw mm2, mm0 + mov rax, rbp + + pop rbp + mov rsi, arg(4) ;Results + + paddw mm1, mm2 + movd [rsi], mm1 + + movd mm2, QWORD PTR [rdx+rax] + movd mm1, QWORD PTR [rbx+rax] + + punpcklbw mm3, mm2 + punpcklbw mm7, mm1 + + psadbw mm3, mm0 + psadbw mm7, mm0 + + movd mm2, QWORD PTR [rdi] + movd mm1, QWORD PTR [rdi+rax] + + paddw mm3, mm4 + paddw mm7, mm5 + + movd [rsi+4], mm3 + punpcklbw mm2, mm1 + + movd [rsi+8], mm7 + psadbw mm2, mm0 + + paddw mm2, mm6 + movd [rsi+12], mm2 + + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/sad_ssse3.asm b/vp8/encoder/x86/sad_ssse3.asm new file mode 100644 index 0000000..1bb9561 --- /dev/null +++ b/vp8/encoder/x86/sad_ssse3.asm
@@ -0,0 +1,367 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%idefine QWORD + +%macro PROCESS_16X2X3 1 +%if %1 + movdqa xmm0, [rsi] + lddqu xmm5, [rdi] + lddqu xmm6, [rdi+1] + lddqu xmm7, [rdi+2] + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, [rsi] + lddqu xmm1, [rdi] + lddqu xmm2, [rdi+1] + lddqu xmm3, [rdi+2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, QWORD PTR [rsi+rax] + lddqu xmm1, QWORD PTR [rdi+rdx] + lddqu xmm2, QWORD PTR [rdi+rdx+1] + lddqu xmm3, QWORD PTR [rdi+rdx+2] + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_16X2X3_OFFSET 2 +%if %1 + movdqa xmm0, [rsi] + movdqa xmm4, [rdi] + movdqa xmm7, [rdi+16] + + movdqa xmm5, xmm7 + palignr xmm5, xmm4, %2 + + movdqa xmm6, xmm7 + palignr xmm6, xmm4, (%2+1) + + palignr xmm7, xmm4, (%2+2) + + psadbw xmm5, xmm0 + psadbw xmm6, xmm0 + psadbw xmm7, xmm0 +%else + movdqa xmm0, [rsi] + movdqa xmm4, [rdi] + movdqa xmm3, [rdi+16] + + movdqa xmm1, xmm3 + palignr xmm1, xmm4, %2 + + movdqa xmm2, xmm3 + palignr xmm2, xmm4, (%2+1) + + palignr xmm3, xmm4, (%2+2) + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endif + movdqa xmm0, QWORD PTR [rsi+rax] + movdqa xmm4, QWORD PTR [rdi+rdx] + movdqa xmm3, QWORD PTR [rdi+rdx+16] + + movdqa xmm1, xmm3 + palignr xmm1, xmm4, %2 + + movdqa xmm2, xmm3 + palignr xmm2, xmm4, (%2+1) + + palignr xmm3, xmm4, (%2+2) + + lea rsi, [rsi+rax*2] + lea rdi, [rdi+rdx*2] + + psadbw xmm1, xmm0 + psadbw xmm2, xmm0 + psadbw xmm3, xmm0 + + paddw xmm5, xmm1 + paddw xmm6, xmm2 + paddw xmm7, xmm3 +%endmacro + +%macro PROCESS_16X16X3_OFFSET 2 +%2_aligned_by_%1: + + sub rdi, %1 + + PROCESS_16X2X3_OFFSET 1, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + + jmp %2_store_off + +%endmacro + +%macro PROCESS_16X8X3_OFFSET 2 +%2_aligned_by_%1: + + sub rdi, %1 + + PROCESS_16X2X3_OFFSET 1, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + PROCESS_16X2X3_OFFSET 0, %1 + + jmp %2_store_off + +%endmacro + +;void int vp8_sad16x16x3_ssse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x16x3_ssse3) +sym(vp8_sad16x16x3_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rcx + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rdx, 0xf + and rdx, rdi + + jmp vp8_sad16x16x3_ssse3_skiptable +vp8_sad16x16x3_ssse3_jumptable: + dd vp8_sad16x16x3_ssse3_aligned_by_0 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_1 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_2 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_3 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_4 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_5 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_6 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_7 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_8 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_9 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_10 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_11 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_12 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_13 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_14 - vp8_sad16x16x3_ssse3_do_jump + dd vp8_sad16x16x3_ssse3_aligned_by_15 - vp8_sad16x16x3_ssse3_do_jump +vp8_sad16x16x3_ssse3_skiptable: + + call vp8_sad16x16x3_ssse3_do_jump +vp8_sad16x16x3_ssse3_do_jump: + pop rcx ; get the address of do_jump + mov rax, vp8_sad16x16x3_ssse3_jumptable - vp8_sad16x16x3_ssse3_do_jump + add rax, rcx ; get the absolute address of vp8_sad16x16x3_ssse3_jumptable + + movsxd rax, dword [rax + 4*rdx] ; get the 32 bit offset from the jumptable + add rcx, rax + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + jmp rcx + + PROCESS_16X16X3_OFFSET 0, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 1, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 2, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 3, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 4, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 5, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 6, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 7, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 8, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 9, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 10, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 11, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 12, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 13, vp8_sad16x16x3_ssse3 + PROCESS_16X16X3_OFFSET 14, vp8_sad16x16x3_ssse3 + +vp8_sad16x16x3_ssse3_aligned_by_15: + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + +vp8_sad16x16x3_ssse3_store_off: + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rcx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void int vp8_sad16x8x3_ssse3( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride, +; int *results) +global sym(vp8_sad16x8x3_ssse3) +sym(vp8_sad16x8x3_ssse3): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + push rcx + ; end prolog + + mov rsi, arg(0) ;src_ptr + mov rdi, arg(2) ;ref_ptr + + mov rdx, 0xf + and rdx, rdi + + jmp vp8_sad16x8x3_ssse3_skiptable +vp8_sad16x8x3_ssse3_jumptable: + dd vp8_sad16x8x3_ssse3_aligned_by_0 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_1 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_2 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_3 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_4 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_5 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_6 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_7 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_8 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_9 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_10 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_11 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_12 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_13 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_14 - vp8_sad16x8x3_ssse3_do_jump + dd vp8_sad16x8x3_ssse3_aligned_by_15 - vp8_sad16x8x3_ssse3_do_jump +vp8_sad16x8x3_ssse3_skiptable: + + call vp8_sad16x8x3_ssse3_do_jump +vp8_sad16x8x3_ssse3_do_jump: + pop rcx ; get the address of do_jump + mov rax, vp8_sad16x8x3_ssse3_jumptable - vp8_sad16x8x3_ssse3_do_jump + add rax, rcx ; get the absolute address of vp8_sad16x8x3_ssse3_jumptable + + movsxd rax, dword [rax + 4*rdx] ; get the 32 bit offset from the jumptable + add rcx, rax + + movsxd rax, dword ptr arg(1) ;src_stride + movsxd rdx, dword ptr arg(3) ;ref_stride + + jmp rcx + + PROCESS_16X8X3_OFFSET 0, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 1, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 2, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 3, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 4, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 5, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 6, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 7, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 8, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 9, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 10, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 11, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 12, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 13, vp8_sad16x8x3_ssse3 + PROCESS_16X8X3_OFFSET 14, vp8_sad16x8x3_ssse3 + +vp8_sad16x8x3_ssse3_aligned_by_15: + + PROCESS_16X2X3 1 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + PROCESS_16X2X3 0 + +vp8_sad16x8x3_ssse3_store_off: + mov rdi, arg(4) ;Results + + movq xmm0, xmm5 + psrldq xmm5, 8 + + paddw xmm0, xmm5 + movd [rdi], xmm0 +;- + movq xmm0, xmm6 + psrldq xmm6, 8 + + paddw xmm0, xmm6 + movd [rdi+4], xmm0 +;- + movq xmm0, xmm7 + psrldq xmm7, 8 + + paddw xmm0, xmm7 + movd [rdi+8], xmm0 + + ; begin epilog + pop rcx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/subtract_mmx.asm b/vp8/encoder/x86/subtract_mmx.asm new file mode 100644 index 0000000..ce3e610 --- /dev/null +++ b/vp8/encoder/x86/subtract_mmx.asm
@@ -0,0 +1,431 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;void vp8_subtract_b_mmx_impl(unsigned char *z, int src_stride, +; unsigned short *diff, unsigned char *Predictor, +; int pitch); +global sym(vp8_subtract_b_mmx_impl) +sym(vp8_subtract_b_mmx_impl) + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + + mov rdi, arg(2) ;diff + mov rax, arg(3) ;Predictor + mov rsi, arg(0) ;z + movsxd rdx, dword ptr arg(1);src_stride; + movsxd rcx, dword ptr arg(4);pitch + pxor mm7, mm7 + + movd mm0, [rsi] + movd mm1, [rax] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi], mm0 + + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*2],mm0 + + + movd mm0, [rsi+rdx*2] + movd mm1, [rax+rcx*2] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*4], mm0 + + lea rsi, [rsi+rdx*2] + lea rcx, [rcx+rcx*2] + + + + movd mm0, [rsi+rdx] + movd mm1, [rax+rcx] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm0, mm1 + movq [rdi+rcx*2], mm0 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_subtract_mby_mmx(short *diff, unsigned char *src, unsigned char *pred, int stride) +global sym(vp8_subtract_mby_mmx) +sym(vp8_subtract_mby_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + ; end prolog + + + mov rsi, arg(1) ;src + mov rdi, arg(0) ;diff + + mov rax, arg(2) ;pred + movsxd rdx, dword ptr arg(3) ;stride + + mov rcx, 16 + pxor mm0, mm0 + +submby_loop: + + movq mm1, [rsi] + movq mm3, [rax] + + movq mm2, mm1 + movq mm4, mm3 + + punpcklbw mm1, mm0 + punpcklbw mm3, mm0 + + punpckhbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm3 + psubw mm2, mm4 + + movq [rdi], mm1 + movq [rdi+8], mm2 + + + movq mm1, [rsi+8] + movq mm3, [rax+8] + + movq mm2, mm1 + movq mm4, mm3 + + punpcklbw mm1, mm0 + punpcklbw mm3, mm0 + + punpckhbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm3 + psubw mm2, mm4 + + movq [rdi+16], mm1 + movq [rdi+24], mm2 + + + add rdi, 32 + add rax, 16 + + lea rsi, [rsi+rdx] + + sub rcx, 1 + jnz submby_loop + + pop rdi + pop rsi + ; begin epilog + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_subtract_mbuv_mmx(short *diff, unsigned char *usrc, unsigned char *vsrc, unsigned char *pred, int stride) +global sym(vp8_subtract_mbuv_mmx) +sym(vp8_subtract_mbuv_mmx) + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 5 + push rsi + push rdi + ; end prolog + + ;short *udiff = diff + 256; + ;short *vdiff = diff + 320; + ;unsigned char *upred = pred + 256; + ;unsigned char *vpred = pred + 320; + + ;unsigned char *z = usrc; + ;unsigned short *diff = udiff; + ;unsigned char *Predictor= upred; + + mov rdi, arg(0) ;diff + mov rax, arg(3) ;pred + mov rsi, arg(1) ;z = usrc + add rdi, 256*2 ;diff = diff + 256 (shorts) + add rax, 256 ;Predictor = pred + 256 + movsxd rdx, dword ptr arg(4) ;stride; + pxor mm7, mm7 + + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + + + movq mm0, [rsi+rdx] + movq mm1, [rax+8] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+16], mm0 + movq [rdi+24], mm3 + + movq mm0, [rsi+rdx*2] + movq mm1, [rax+16] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+32], mm0 + movq [rdi+40], mm3 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi+rdx] + movq mm1, [rax+24] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + + movq [rdi+48], mm0 + movq [rdi+56], mm3 + + + add rdi, 64 + add rax, 32 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + + + movq mm0, [rsi+rdx] + movq mm1, [rax+8] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+16], mm0 + movq [rdi+24], mm3 + + movq mm0, [rsi+rdx*2] + movq mm1, [rax+16] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+32], mm0 + movq [rdi+40], mm3 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi+rdx] + movq mm1, [rax+24] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + + movq [rdi+48], mm0 + movq [rdi+56], mm3 + + ;unsigned char *z = vsrc; + ;unsigned short *diff = vdiff; + ;unsigned char *Predictor= vpred; + + mov rdi, arg(0) ;diff + mov rax, arg(3) ;pred + mov rsi, arg(2) ;z = usrc + add rdi, 320*2 ;diff = diff + 320 (shorts) + add rax, 320 ;Predictor = pred + 320 + movsxd rdx, dword ptr arg(4) ;stride; + pxor mm7, mm7 + + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + + + movq mm0, [rsi+rdx] + movq mm1, [rax+8] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+16], mm0 + movq [rdi+24], mm3 + + movq mm0, [rsi+rdx*2] + movq mm1, [rax+16] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+32], mm0 + movq [rdi+40], mm3 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi+rdx] + movq mm1, [rax+24] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + + movq [rdi+48], mm0 + movq [rdi+56], mm3 + + + add rdi, 64 + add rax, 32 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi] + movq mm1, [rax] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi], mm0 + movq [rdi+8], mm3 + + + movq mm0, [rsi+rdx] + movq mm1, [rax+8] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+16], mm0 + movq [rdi+24], mm3 + + movq mm0, [rsi+rdx*2] + movq mm1, [rax+16] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + movq [rdi+32], mm0 + movq [rdi+40], mm3 + lea rsi, [rsi+rdx*2] + + + movq mm0, [rsi+rdx] + movq mm1, [rax+24] + movq mm3, mm0 + movq mm4, mm1 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + punpckhbw mm3, mm7 + punpckhbw mm4, mm7 + psubw mm0, mm1 + psubw mm3, mm4 + + movq [rdi+48], mm0 + movq [rdi+56], mm3 + + ; begin epilog + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret
diff --git a/vp8/encoder/x86/variance_impl_mmx.asm b/vp8/encoder/x86/variance_impl_mmx.asm new file mode 100644 index 0000000..d0da82a --- /dev/null +++ b/vp8/encoder/x86/variance_impl_mmx.asm
@@ -0,0 +1,980 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +;unsigned int vp8_get_mb_ss_mmx( short *src_ptr ) +global sym(vp8_get_mb_ss_mmx) +sym(vp8_get_mb_ss_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + sub rsp, 8 + ; end prolog + + mov rax, arg(0) ;src_ptr + mov rcx, 16 + pxor mm4, mm4 + +NEXTROW: + movq mm0, [rax] + movq mm1, [rax+8] + movq mm2, [rax+16] + movq mm3, [rax+24] + pmaddwd mm0, mm0 + pmaddwd mm1, mm1 + pmaddwd mm2, mm2 + pmaddwd mm3, mm3 + + paddd mm4, mm0 + paddd mm4, mm1 + paddd mm4, mm2 + paddd mm4, mm3 + + add rax, 32 + dec rcx + ja NEXTROW + movq QWORD PTR [rsp], mm4 + + ;return sum[0]+sum[1]; + movsxd rax, dword ptr [rsp] + movsxd rcx, dword ptr [rsp+4] + add rax, rcx + + + ; begin epilog + add rsp, 8 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_get8x8var_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *SSE, +; int *Sum +;) +global sym(vp8_get8x8var_mmx) +sym(vp8_get8x8var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + push rbx + sub rsp, 16 + ; end prolog + + + pxor mm5, mm5 ; Blank mmx6 + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + + ; Row 1 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm1, [rbx] ; Copy eight bytes to mm1 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + + ; Row 2 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 3 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 4 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 5 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + ; movq mm4, [rbx + rdx] + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 6 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 7 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Row 8 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm2, mm0 ; Take copies + movq mm3, mm1 ; Take copies + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + punpckhbw mm2, mm6 ; unpack to higher prrcision + punpckhbw mm3, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + psubsw mm2, mm3 ; A-B (high order) to MM2 + + paddw mm5, mm0 ; accumulate differences in mm5 + paddw mm5, mm2 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + pmaddwd mm2, mm2 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + paddd mm7, mm0 ; accumulate in mm7 + paddd mm7, mm2 ; accumulate in mm7 + + ; Now accumulate the final results. + movq QWORD PTR [rsp+8], mm5 ; copy back accumulated results into normal memory + movq QWORD PTR [rsp], mm7 ; copy back accumulated results into normal memory + movsx rdx, WORD PTR [rsp+8] + movsx rcx, WORD PTR [rsp+10] + movsx rbx, WORD PTR [rsp+12] + movsx rax, WORD PTR [rsp+14] + add rdx, rcx + add rbx, rax + add rdx, rbx ;XSum + movsxd rax, DWORD PTR [rsp] + movsxd rcx, DWORD PTR [rsp+4] + add rax, rcx ;XXSum + mov rsi, arg(4) ;SSE + mov rdi, arg(5) ;Sum + mov dword ptr [rsi], eax + mov dword ptr [rdi], edx + xor rax, rax ; return 0 + + + ; begin epilog + add rsp, 16 + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int +;vp8_get4x4var_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride, +; unsigned int *SSE, +; int *Sum +;) +global sym(vp8_get4x4var_mmx) +sym(vp8_get4x4var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + push rsi + push rdi + push rbx + sub rsp, 16 + ; end prolog + + + pxor mm5, mm5 ; Blank mmx6 + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + + ; Row 1 + movq mm0, [rax] ; Copy eight bytes to mm0 + movq mm1, [rbx] ; Copy eight bytes to mm1 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + + ; Row 2 + movq mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 3 + movq mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movq mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 4 + movq mm0, [rax] ; Copy eight bytes to mm0 + + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + + paddw mm5, mm0 ; accumulate differences in mm5 + + pmaddwd mm0, mm0 ; square and accumulate + paddd mm7, mm0 ; accumulate in mm7 + + + ; Now accumulate the final results. + movq QWORD PTR [rsp+8], mm5 ; copy back accumulated results into normal memory + movq QWORD PTR [rsp], mm7 ; copy back accumulated results into normal memory + movsx rdx, WORD PTR [rsp+8] + movsx rcx, WORD PTR [rsp+10] + movsx rbx, WORD PTR [rsp+12] + movsx rax, WORD PTR [rsp+14] + add rdx, rcx + add rbx, rax + add rdx, rbx ;XSum + movsxd rax, DWORD PTR [rsp] + movsxd rcx, DWORD PTR [rsp+4] + add rax, rcx ;XXSum + mov rsi, arg(4) ;SSE + mov rdi, arg(5) ;Sum + mov dword ptr [rsi], eax + mov dword ptr [rdi], edx + xor rax, rax ; return 0 + + + ; begin epilog + add rsp, 16 + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int +;vp8_get4x4sse_cs_mmx +;( +; unsigned char *src_ptr, +; int source_stride, +; unsigned char *ref_ptr, +; int recon_stride +;) +global sym(vp8_get4x4sse_cs_mmx) +sym(vp8_get4x4sse_cs_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + push rsi + push rdi + push rbx + ; end prolog + + + pxor mm6, mm6 ; Blank mmx7 + pxor mm7, mm7 ; Blank mmx7 + + mov rax, arg(0) ;[src_ptr] ; Load base addresses + mov rbx, arg(2) ;[ref_ptr] + movsxd rcx, dword ptr arg(1) ;[source_stride] + movsxd rdx, dword ptr arg(3) ;[recon_stride] + ; Row 1 + movd mm0, [rax] ; Copy eight bytes to mm0 + movd mm1, [rbx] ; Copy eight bytes to mm1 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 2 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 3 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm1, mm6 + punpcklbw mm0, mm6 ; unpack to higher prrcision + psubsw mm0, mm1 ; A-B (low order) to MM0 + + pmaddwd mm0, mm0 ; square and accumulate + add rbx,rdx ; Inc pointer into ref data + add rax,rcx ; Inc pointer into the new data + movd mm1, [rbx] ; Copy eight bytes to mm1 + paddd mm7, mm0 ; accumulate in mm7 + + ; Row 4 + movd mm0, [rax] ; Copy eight bytes to mm0 + punpcklbw mm0, mm6 ; unpack to higher prrcision + punpcklbw mm1, mm6 + psubsw mm0, mm1 ; A-B (low order) to MM0 + pmaddwd mm0, mm0 ; square and accumulate + paddd mm7, mm0 ; accumulate in mm7 + + movq mm0, mm7 ; + psrlq mm7, 32 + + paddd mm0, mm7 + movd rax, mm0 + + + ; begin epilog + pop rbx + pop rdi + pop rsi + UNSHADOW_ARGS + pop rbp + ret + +%define mmx_filter_shift 7 + +;void vp8_filter_block2d_bil4x4_var_mmx +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned short *HFilter, +; unsigned short *VFilter, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_filter_block2d_bil4x4_var_mmx) +sym(vp8_filter_block2d_bil4x4_var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 8 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + + pxor mm6, mm6 ; + pxor mm7, mm7 ; + + mov rax, arg(4) ;HFilter ; + mov rdx, arg(5) ;VFilter ; + + mov rsi, arg(0) ;ref_ptr ; + mov rdi, arg(2) ;src_ptr ; + + mov rcx, 4 ; + pxor mm0, mm0 ; + + movd mm1, [rsi] ; + movd mm3, [rsi+1] ; + + punpcklbw mm1, mm0 ; + pmullw mm1, [rax] ; + + punpcklbw mm3, mm0 ; + pmullw mm3, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm1, [mmx_bi_rd GLOBAL] ; + + psraw mm1, mmx_filter_shift ; + movq mm5, mm1 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + add rsi, r8 +%endif + +filter_block2d_bil4x4_var_mmx_loop: + + movd mm1, [rsi] ; + movd mm3, [rsi+1] ; + + punpcklbw mm1, mm0 ; + pmullw mm1, [rax] ; + + punpcklbw mm3, mm0 ; + pmullw mm3, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm1, [mmx_bi_rd GLOBAL] ; + + psraw mm1, mmx_filter_shift ; + movq mm3, mm5 ; + + movq mm5, mm1 ; + pmullw mm3, [rdx] ; + + pmullw mm1, [rdx+8] ; + paddw mm1, mm3 ; + + + paddw mm1, [mmx_bi_rd GLOBAL] ; + psraw mm1, mmx_filter_shift ; + + movd mm3, [rdi] ; + punpcklbw mm3, mm0 ; + + psubw mm1, mm3 ; + paddw mm6, mm1 ; + + pmaddwd mm1, mm1 ; + paddd mm7, mm1 ; + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; + add rdi, dword ptr arg(3) ;src_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz filter_block2d_bil4x4_var_mmx_loop ; + + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rdi, arg(6) ;sum + mov rsi, arg(7) ;sumsquared + + movd dword ptr [rdi], mm2 ; + movd dword ptr [rsi], mm4 ; + + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + + +;void vp8_filter_block2d_bil_var_mmx +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; unsigned short *HFilter, +; unsigned short *VFilter, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_filter_block2d_bil_var_mmx) +sym(vp8_filter_block2d_bil_var_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + pxor mm6, mm6 ; + pxor mm7, mm7 ; + mov rax, arg(5) ;HFilter ; + + mov rdx, arg(6) ;VFilter ; + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + + pxor mm0, mm0 ; + movq mm1, [rsi] ; + + movq mm3, [rsi+1] ; + movq mm2, mm1 ; + + movq mm4, mm3 ; + punpcklbw mm1, mm0 ; + + punpckhbw mm2, mm0 ; + pmullw mm1, [rax] ; + + pmullw mm2, [rax] ; + punpcklbw mm3, mm0 ; + + punpckhbw mm4, mm0 ; + pmullw mm3, [rax+8] ; + + pmullw mm4, [rax+8] ; + paddw mm1, mm3 ; + + paddw mm2, mm4 ; + paddw mm1, [mmx_bi_rd GLOBAL] ; + + psraw mm1, mmx_filter_shift ; + paddw mm2, [mmx_bi_rd GLOBAL] ; + + psraw mm2, mmx_filter_shift ; + movq mm5, mm1 + + packuswb mm5, mm2 ; +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + add rsi, r8 +%endif + +filter_block2d_bil_var_mmx_loop: + + movq mm1, [rsi] ; + movq mm3, [rsi+1] ; + + movq mm2, mm1 ; + movq mm4, mm3 ; + + punpcklbw mm1, mm0 ; + punpckhbw mm2, mm0 ; + + pmullw mm1, [rax] ; + pmullw mm2, [rax] ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + pmullw mm3, [rax+8] ; + pmullw mm4, [rax+8] ; + + paddw mm1, mm3 ; + paddw mm2, mm4 ; + + paddw mm1, [mmx_bi_rd GLOBAL] ; + psraw mm1, mmx_filter_shift ; + + paddw mm2, [mmx_bi_rd GLOBAL] ; + psraw mm2, mmx_filter_shift ; + + movq mm3, mm5 ; + movq mm4, mm5 ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + movq mm5, mm1 ; + packuswb mm5, mm2 ; + + pmullw mm3, [rdx] ; + pmullw mm4, [rdx] ; + + pmullw mm1, [rdx+8] ; + pmullw mm2, [rdx+8] ; + + paddw mm1, mm3 ; + paddw mm2, mm4 ; + + paddw mm1, [mmx_bi_rd GLOBAL] ; + paddw mm2, [mmx_bi_rd GLOBAL] ; + + psraw mm1, mmx_filter_shift ; + psraw mm2, mmx_filter_shift ; + + movq mm3, [rdi] ; + movq mm4, mm3 ; + + punpcklbw mm3, mm0 ; + punpckhbw mm4, mm0 ; + + psubw mm1, mm3 ; + psubw mm2, mm4 ; + + paddw mm6, mm1 ; + pmaddwd mm1, mm1 ; + + paddw mm6, mm2 ; + pmaddwd mm2, mm2 ; + + paddd mm7, mm1 ; + paddd mm7, mm2 ; + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; + add rdi, dword ptr arg(3) ;src_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + movsxd r9, dword ptr arg(3) ;src_pixels_per_line ; + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz filter_block2d_bil_var_mmx_loop ; + + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rdi, arg(7) ;sum + mov rsi, arg(8) ;sumsquared + + movd dword ptr [rdi], mm2 ; + movd dword ptr [rsi], mm4 ; + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;unsigned int vp8_get16x16pred_error_mmx +;( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride +;) +global sym(vp8_get16x16pred_error_mmx) +sym(vp8_get16x16pred_error_mmx): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + mov rsi, arg(0) ;DWORD PTR [src_ptr] + mov rdi, arg(2) ;DWORD PTR [ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[src_stride] + movsxd rdx, DWORD PTR arg(3) ;[ref_stride] + + pxor mm0, mm0 ; clear xmm0 for unpack + pxor mm7, mm7 ; clear xmm7 for accumulating diffs + + pxor mm6, mm6 ; clear xmm6 for accumulating sse + mov rcx, 16 + +var16loop: + + movq mm1, [rsi] + movq mm2, [rdi] + + movq mm3, mm1 + movq mm4, mm2 + + punpcklbw mm1, mm0 + punpckhbw mm3, mm0 + + punpcklbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm2 + psubw mm3, mm4 + + paddw mm7, mm1 + pmaddwd mm1, mm1 + + paddw mm7, mm3 + pmaddwd mm3, mm3 + + paddd mm6, mm1 + paddd mm6, mm3 + + + movq mm1, [rsi+8] + movq mm2, [rdi+8] + + movq mm3, mm1 + movq mm4, mm2 + + punpcklbw mm1, mm0 + punpckhbw mm3, mm0 + + punpcklbw mm2, mm0 + punpckhbw mm4, mm0 + + psubw mm1, mm2 + psubw mm3, mm4 + + paddw mm7, mm1 + pmaddwd mm1, mm1 + + paddw mm7, mm3 + pmaddwd mm3, mm3 + + paddd mm6, mm1 + paddd mm6, mm3 + + add rsi, rax + add rdi, rdx + + sub rcx, 1 + jnz var16loop + + + movq mm1, mm6 + pxor mm6, mm6 + + pxor mm5, mm5 + punpcklwd mm6, mm7 + + punpckhwd mm5, mm7 + psrad mm5, 16 + + psrad mm6, 16 + paddd mm6, mm5 + + movq mm2, mm1 + psrlq mm1, 32 + + paddd mm2, mm1 + movq mm7, mm6 + + psrlq mm6, 32 + paddd mm6, mm7 + + movd DWORD PTR [rsp], mm6 ;Sum + movd DWORD PTR [rsp+4], mm2 ;SSE + + ; return (SSE-((Sum*Sum)>>8)); + movsxd rdx, dword ptr [rsp] + imul rdx, rdx + sar rdx, 8 + movsxd rax, dword ptr [rsp + 4] + sub rax, rdx + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +SECTION_RODATA +;short mmx_bi_rd[4] = { 64, 64, 64, 64}; +align 16 +mmx_bi_rd: + times 4 dw 64
diff --git a/vp8/encoder/x86/variance_impl_sse2.asm b/vp8/encoder/x86/variance_impl_sse2.asm new file mode 100644 index 0000000..7e5ee28 --- /dev/null +++ b/vp8/encoder/x86/variance_impl_sse2.asm
@@ -0,0 +1,975 @@ +; +; Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +; +; Use of this source code is governed by a BSD-style license and patent +; grant that can be found in the LICENSE file in the root of the source +; tree. All contributing project authors may be found in the AUTHORS +; file in the root of the source tree. +; + + +%include "vpx_ports/x86_abi_support.asm" + +%define xmm_filter_shift 7 + +;unsigned int vp8_get_mb_ss_sse2 +;( +; short *src_ptr +;) +global sym(vp8_get_mb_ss_sse2) +sym(vp8_get_mb_ss_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 1 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + + mov rax, arg(0) ;[src_ptr] + mov rcx, 8 + pxor xmm4, xmm4 + +NEXTROW: + movdqa xmm0, [rax] + movdqa xmm1, [rax+16] + movdqa xmm2, [rax+32] + movdqa xmm3, [rax+48] + pmaddwd xmm0, xmm0 + pmaddwd xmm1, xmm1 + pmaddwd xmm2, xmm2 + pmaddwd xmm3, xmm3 + + paddd xmm0, xmm1 + paddd xmm2, xmm3 + paddd xmm4, xmm0 + paddd xmm4, xmm2 + + add rax, 0x40 + dec rcx + ja NEXTROW + + movdqa xmm3,xmm4 + psrldq xmm4,8 + paddd xmm4,xmm3 + movdqa xmm3,xmm4 + psrldq xmm4,4 + paddd xmm4,xmm3 + movd rax,xmm4 + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_get16x16var_sse2 +;( +; unsigned char * src_ptr, +; int source_stride, +; unsigned char * ref_ptr, +; int recon_stride, +; unsigned int * SSE, +; int * Sum +;) +global sym(vp8_get16x16var_sse2) +sym(vp8_get16x16var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + mov rsi, arg(0) ;[src_ptr] + mov rdi, arg(2) ;[ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[source_stride] + movsxd rdx, DWORD PTR arg(3) ;[recon_stride] + + pxor xmm0, xmm0 ; clear xmm0 for unpack + pxor xmm7, xmm7 ; clear xmm7 for accumulating diffs + + pxor xmm6, xmm6 ; clear xmm6 for accumulating sse + mov rcx, 16 + +var16loop: + movdqu xmm1, XMMWORD PTR [rsi] + movdqu xmm2, XMMWORD PTR [rdi] + + movdqa xmm3, xmm1 + movdqa xmm4, xmm2 + + + punpcklbw xmm1, xmm0 + punpckhbw xmm3, xmm0 + + punpcklbw xmm2, xmm0 + punpckhbw xmm4, xmm0 + + + psubw xmm1, xmm2 + psubw xmm3, xmm4 + + paddw xmm7, xmm1 + pmaddwd xmm1, xmm1 + + paddw xmm7, xmm3 + pmaddwd xmm3, xmm3 + + paddd xmm6, xmm1 + paddd xmm6, xmm3 + + add rsi, rax + add rdi, rdx + + sub rcx, 1 + jnz var16loop + + + movdqa xmm1, xmm6 + pxor xmm6, xmm6 + + pxor xmm5, xmm5 + punpcklwd xmm6, xmm7 + + punpckhwd xmm5, xmm7 + psrad xmm5, 16 + + psrad xmm6, 16 + paddd xmm6, xmm5 + + movdqa xmm2, xmm1 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + movdqa xmm7, xmm6 + + paddd xmm1, xmm2 + punpckldq xmm6, xmm0 + + punpckhdq xmm7, xmm0 + paddd xmm6, xmm7 + + movdqa xmm2, xmm1 + movdqa xmm7, xmm6 + + psrldq xmm1, 8 + psrldq xmm6, 8 + + paddd xmm7, xmm6 + paddd xmm1, xmm2 + + mov rax, arg(5) ;[Sum] + mov rdi, arg(4) ;[SSE] + + movd DWORD PTR [rax], xmm7 + movd DWORD PTR [rdi], xmm1 + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;unsigned int vp8_get16x16pred_error_sse2 +;( +; unsigned char *src_ptr, +; int src_stride, +; unsigned char *ref_ptr, +; int ref_stride +;) +global sym(vp8_get16x16pred_error_sse2) +sym(vp8_get16x16pred_error_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 4 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + mov rsi, arg(0) ;[src_ptr] + mov rdi, arg(2) ;[ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[src_stride] + movsxd rdx, DWORD PTR arg(3) ;[ref_stride] + + pxor xmm0, xmm0 ; clear xmm0 for unpack + pxor xmm7, xmm7 ; clear xmm7 for accumulating diffs + + pxor xmm6, xmm6 ; clear xmm6 for accumulating sse + mov rcx, 16 + +var16peloop: + movdqu xmm1, XMMWORD PTR [rsi] + movdqu xmm2, XMMWORD PTR [rdi] + + movdqa xmm3, xmm1 + movdqa xmm4, xmm2 + + punpcklbw xmm1, xmm0 + punpckhbw xmm3, xmm0 + + punpcklbw xmm2, xmm0 + punpckhbw xmm4, xmm0 + + psubw xmm1, xmm2 + psubw xmm3, xmm4 + + paddw xmm7, xmm1 + pmaddwd xmm1, xmm1 + + paddw xmm7, xmm3 + pmaddwd xmm3, xmm3 + + paddd xmm6, xmm1 + paddd xmm6, xmm3 + + add rsi, rax + add rdi, rdx + + sub rcx, 1 + jnz var16peloop + + + movdqa xmm1, xmm6 + pxor xmm6, xmm6 + + pxor xmm5, xmm5 + punpcklwd xmm6, xmm7 + + punpckhwd xmm5, xmm7 + psrad xmm5, 16 + + psrad xmm6, 16 + paddd xmm6, xmm5 + + movdqa xmm2, xmm1 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + movdqa xmm7, xmm6 + + paddd xmm1, xmm2 + punpckldq xmm6, xmm0 + + punpckhdq xmm7, xmm0 + paddd xmm6, xmm7 + + movdqa xmm2, xmm1 + movdqa xmm7, xmm6 + + psrldq xmm1, 8 + psrldq xmm6, 8 + + paddd xmm7, xmm6 + paddd xmm1, xmm2 + + movd DWORD PTR [rsp], xmm7 ;Sum + movd DWORD PTR [rsp+4], xmm1 ;SSE + + ; return (SSE-((Sum*Sum)>>8)); + movsxd rdx, dword ptr [rsp] + imul rdx, rdx + sar rdx, 8 + movsxd rax, dword ptr [rsp + 4] + sub rax, rdx + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + + +;unsigned int vp8_get8x8var_sse2 +;( +; unsigned char * src_ptr, +; int source_stride, +; unsigned char * ref_ptr, +; int recon_stride, +; unsigned int * SSE, +; int * Sum +;) +global sym(vp8_get8x8var_sse2) +sym(vp8_get8x8var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 6 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + mov rsi, arg(0) ;[src_ptr] + mov rdi, arg(2) ;[ref_ptr] + + movsxd rax, DWORD PTR arg(1) ;[source_stride] + movsxd rdx, DWORD PTR arg(3) ;[recon_stride] + + pxor xmm0, xmm0 ; clear xmm0 for unpack + pxor xmm7, xmm7 ; clear xmm7 for accumulating diffs + + movq xmm1, QWORD PTR [rsi] + movq xmm2, QWORD PTR [rdi] + + punpcklbw xmm1, xmm0 + punpcklbw xmm2, xmm0 + + psubsw xmm1, xmm2 + paddw xmm7, xmm1 + + pmaddwd xmm1, xmm1 + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + movq xmm2, QWORD PTR[rsi + rax * 2] + movq xmm3, QWORD PTR[rdi + rdx * 2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + movq xmm2, QWORD PTR[rsi + rax *2] + movq xmm3, QWORD PTR[rdi + rdx *2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + movq xmm2, QWORD PTR[rsi + rax *2] + movq xmm3, QWORD PTR[rdi + rdx *2] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + lea rsi, [rsi + rax * 2] + lea rdi, [rdi + rdx * 2] + + movq xmm2, QWORD PTR[rsi + rax] + movq xmm3, QWORD PTR[rdi + rdx] + + punpcklbw xmm2, xmm0 + punpcklbw xmm3, xmm0 + + psubsw xmm2, xmm3 + paddw xmm7, xmm2 + + pmaddwd xmm2, xmm2 + paddd xmm1, xmm2 + + + movdqa xmm6, xmm7 + punpcklwd xmm6, xmm0 + + punpckhwd xmm7, xmm0 + movdqa xmm2, xmm1 + + paddw xmm6, xmm7 + punpckldq xmm1, xmm0 + + punpckhdq xmm2, xmm0 + movdqa xmm7, xmm6 + + paddd xmm1, xmm2 + punpckldq xmm6, xmm0 + + punpckhdq xmm7, xmm0 + paddw xmm6, xmm7 + + movdqa xmm2, xmm1 + movdqa xmm7, xmm6 + + psrldq xmm1, 8 + psrldq xmm6, 8 + + paddw xmm7, xmm6 + paddd xmm1, xmm2 + + mov rax, arg(5) ;[Sum] + mov rdi, arg(4) ;[SSE] + + movd rdx, xmm7 + movsx rcx, dx + + mov dword ptr [rax], ecx + movd DWORD PTR [rdi], xmm1 + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + +;void vp8_filter_block2d_bil_var_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; unsigned short *HFilter, +; unsigned short *VFilter, +; int *sum, +; unsigned int *sumsquared;; +; +;) +global sym(vp8_filter_block2d_bil_var_sse2) +sym(vp8_filter_block2d_bil_var_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 9 + GET_GOT rbx + push rsi + push rdi + sub rsp, 16 + ; end prolog + + pxor xmm6, xmm6 ; + pxor xmm7, xmm7 ; + mov rax, arg(5) ;HFilter ; + + mov rdx, arg(6) ;VFilter ; + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + + pxor xmm0, xmm0 ; + movq xmm1, QWORD PTR [rsi] ; + + movq xmm3, QWORD PTR [rsi+1] ; + punpcklbw xmm1, xmm0 ; + + pmullw xmm1, [rax] ; + punpcklbw xmm3, xmm0 + ; + pmullw xmm3, [rax+16] ; + paddw xmm1, xmm3 ; + + paddw xmm1, [xmm_bi_rd GLOBAL] ; + psraw xmm1, xmm_filter_shift ; + + movdqa xmm5, xmm1 +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + add rsi, r8 +%endif +filter_block2d_bil_var_sse2_loop: + + movq xmm1, QWORD PTR [rsi] ; + movq xmm3, QWORD PTR [rsi+1] ; + + punpcklbw xmm1, xmm0 ; + pmullw xmm1, [rax] ; + + punpcklbw xmm3, xmm0 ; + pmullw xmm3, [rax+16] ; + + paddw xmm1, xmm3 ; + paddw xmm1, [xmm_bi_rd GLOBAL] ; + + psraw xmm1, xmm_filter_shift ; + movdqa xmm3, xmm5 ; + + movdqa xmm5, xmm1 ; + pmullw xmm3, [rdx] ; + + pmullw xmm1, [rdx+16] ; + paddw xmm1, xmm3 ; + + paddw xmm1, [xmm_bi_rd GLOBAL] ; + psraw xmm1, xmm_filter_shift ; + + movq xmm3, QWORD PTR [rdi] ; + punpcklbw xmm3, xmm0 ; + + psubw xmm1, xmm3 ; + paddw xmm6, xmm1 ; + + pmaddwd xmm1, xmm1 ; + paddd xmm7, xmm1 ; + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; + add rdi, dword ptr arg(3) ;src_pixels_per_line ; +%else + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line ; + movsxd r9, dword ptr arg(3) ;src_pixels_per_line ; + add rsi, r8 + add rdi, r9 +%endif + + sub rcx, 1 ; + jnz filter_block2d_bil_var_sse2_loop ; + + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(7) ; sum + mov rdi, arg(8) ; sumsquared + + movd [rsi], mm2 ; xsum + movd [rdi], mm4 ; xxsum + + + ; begin epilog + add rsp, 16 + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_horiz_vert_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_vert_variance16x_h_sse2) +sym(vp8_half_horiz_vert_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; + + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+1] ; xmm3 = s1,s2,s3..s9 + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) horizontal line 1 + +%if ABI_IS_32BIT + add rsi, dword ptr arg(1) ;ref_pixels_per_line ; next source +%else + add rsi, r8 +%endif + +vp8_half_horiz_vert_variance16x_h_1: + + movq xmm1, QWORD PTR [rsi] ; + movq xmm2, QWORD PTR [rsi+1] ; + pavgb xmm1, xmm2 ; xmm1 = avg(xmm1,xmm3) horizontal line i+1 + + pavgb xmm5, xmm1 ; xmm = vertical average of the above + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + + movdqa xmm5, xmm1 ; save xmm1 for use on the next row + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + + sub rcx, 1 ; + jnz vp8_half_horiz_vert_variance16x_h_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_vert_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_vert_variance16x_h_sse2) +sym(vp8_half_vert_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + movsxd rax, dword ptr arg(1) ;ref_pixels_per_line + + pxor xmm0, xmm0 ; +vp8_half_vert_variance16x_h_1: + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+rax] ; xmm3 = s1,s2,s3..s9 + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + + sub rcx, 1 ; + jnz vp8_half_vert_variance16x_h_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +;void vp8_half_horiz_variance16x_h_sse2 +;( +; unsigned char *ref_ptr, +; int ref_pixels_per_line, +; unsigned char *src_ptr, +; int src_pixels_per_line, +; unsigned int Height, +; int *sum, +; unsigned int *sumsquared +;) +global sym(vp8_half_horiz_variance16x_h_sse2) +sym(vp8_half_horiz_variance16x_h_sse2): + push rbp + mov rbp, rsp + SHADOW_ARGS_TO_STACK 7 + GET_GOT rbx + push rsi + push rdi + ; end prolog + +%if ABI_IS_32BIT=0 + movsxd r8, dword ptr arg(1) ;ref_pixels_per_line + movsxd r9, dword ptr arg(3) ;src_pixels_per_line +%endif + + pxor xmm6, xmm6 ; error accumulator + pxor xmm7, xmm7 ; sse eaccumulator + mov rsi, arg(0) ;ref_ptr ; + + mov rdi, arg(2) ;src_ptr ; + movsxd rcx, dword ptr arg(4) ;Height ; + + pxor xmm0, xmm0 ; +vp8_half_horiz_variance16x16_1: + movq xmm5, QWORD PTR [rsi] ; xmm5 = s0,s1,s2..s8 + movq xmm3, QWORD PTR [rsi+1] ; xmm3 = s1,s2,s3..s9 + + pavgb xmm5, xmm3 ; xmm5 = avg(xmm1,xmm3) + punpcklbw xmm5, xmm0 ; xmm5 = words of above + + movq xmm3, QWORD PTR [rdi] ; xmm3 = d0,d1,d2..d8 + punpcklbw xmm3, xmm0 ; xmm3 = words of above + + psubw xmm5, xmm3 ; xmm5 -= xmm3 + paddw xmm6, xmm5 ; xmm6 += accumulated column differences + pmaddwd xmm5, xmm5 ; xmm5 *= xmm5 + paddd xmm7, xmm5 ; xmm7 += accumulated square column differences + +%if ABI_IS_32BIT + add esi, dword ptr arg(1) ;ref_pixels_per_line ; next source + add edi, dword ptr arg(3) ;src_pixels_per_line ; next destination +%else + add rsi, r8 + add rdi, r9 +%endif + sub rcx, 1 ; + jnz vp8_half_horiz_variance16x16_1 ; + + movdq2q mm6, xmm6 ; + movdq2q mm7, xmm7 ; + + psrldq xmm6, 8 + psrldq xmm7, 8 + + movdq2q mm2, xmm6 + movdq2q mm3, xmm7 + + paddw mm6, mm2 + paddd mm7, mm3 + + pxor mm3, mm3 ; + pxor mm2, mm2 ; + + punpcklwd mm2, mm6 ; + punpckhwd mm3, mm6 ; + + paddd mm2, mm3 ; + movq mm6, mm2 ; + + psrlq mm6, 32 ; + paddd mm2, mm6 ; + + psrad mm2, 16 ; + movq mm4, mm7 ; + + psrlq mm4, 32 ; + paddd mm4, mm7 ; + + mov rsi, arg(5) ; sum + mov rdi, arg(6) ; sumsquared + + movd [rsi], mm2 ; + movd [rdi], mm4 ; + + + ; begin epilog + pop rdi + pop rsi + RESTORE_GOT + UNSHADOW_ARGS + pop rbp + ret + + +SECTION_RODATA +; short xmm_bi_rd[8] = { 64, 64, 64, 64,64, 64, 64, 64}; +align 16 +xmm_bi_rd: + times 8 dw 64
diff --git a/vp8/encoder/x86/variance_mmx.c b/vp8/encoder/x86/variance_mmx.c new file mode 100644 index 0000000..4a5b25b --- /dev/null +++ b/vp8/encoder/x86/variance_mmx.c
@@ -0,0 +1,596 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "variance.h" +#include "pragmas.h" +#include "vpx_ports/mem.h" + +extern void filter_block1d_h6_mmx +( + unsigned char *src_ptr, + unsigned short *output_ptr, + unsigned int src_pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + short *vp7_filter +); +extern void filter_block1d_v6_mmx +( + short *src_ptr, + unsigned char *output_ptr, + unsigned int pixels_per_line, + unsigned int pixel_step, + unsigned int output_height, + unsigned int output_width, + short *vp7_filter +); + +extern unsigned int vp8_get_mb_ss_mmx(short *src_ptr); +extern unsigned int vp8_get8x8var_mmx +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +extern unsigned int vp8_get4x4var_mmx +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +extern unsigned int vp8_get4x4sse_cs_mmx +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride +); +extern void vp8_filter_block2d_bil4x4_var_mmx +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); +extern void vp8_filter_block2d_bil_var_mmx +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); +extern unsigned int vp8_get16x16pred_error_mmx +( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride +); + + +void vp8_test_get_mb_ss(void) +{ + short zz[] = + { + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -2, -2, -2, -2, 2, 2, 2, 2, -2, -2, -2, -2, 2, 2, 2, 2, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -3, -3, -3, -3, 3, 3, 3, 3, -3, -3, -3, -3, 3, 3, 3, 3, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + -4, -4, -4, -4, 4, 4, 4, 4, -4, -4, -4, -4, 4, 4, 4, 4, + }; + int s = 0, x = vp8_get_mb_ss_mmx(zz); + { + int y; + + for (y = 0; y < 256; y++) + s += (zz[y] * zz[y]); + } + + x += 0; +} + + +unsigned int vp8_get16x16var_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned *SSE, + unsigned *SUM +) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3, avg; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride + 8, source_stride, ref_ptr + 8 * recon_stride + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + avg = sum0 + sum1 + sum2 + sum3; + + *SSE = var; + *SUM = avg; + return (var - ((avg * avg) >> 8)); + +} + + + + + +unsigned int vp8_variance4x4_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get4x4var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + return (var - ((avg * avg) >> 4)); + +} + +unsigned int vp8_variance8x8_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int var; + int avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + *sse = var; + + return (var - ((avg * avg) >> 6)); + +} + +unsigned int vp8_mse16x16_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride + 8, source_stride, ref_ptr + 8 * recon_stride + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + *sse = var; + return var; +} + + +unsigned int vp8_variance16x16_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3, avg; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride + 8, source_stride, ref_ptr + 8 * recon_stride + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + avg = sum0 + sum1 + sum2 + sum3; + *sse = var; + return (var - ((avg * avg) >> 8)); +} + +unsigned int vp8_variance16x8_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((avg * avg) >> 7)); + +} + + +unsigned int vp8_variance8x16_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + + return (var - ((avg * avg) >> 7)); + +} + + + + +/////////////////////////////////////////////////////////////////////////// +// the mmx function that does the bilinear filtering and var calculation // +// int one pass // +/////////////////////////////////////////////////////////////////////////// +DECLARE_ALIGNED(16, const short, vp8_vp7_bilinear_filters_mmx[8][8]) = +{ + { 128, 128, 128, 128, 0, 0, 0, 0 }, + { 112, 112, 112, 112, 16, 16, 16, 16 }, + { 96, 96, 96, 96, 32, 32, 32, 32 }, + { 80, 80, 80, 80, 48, 48, 48, 48 }, + { 64, 64, 64, 64, 64, 64, 64, 64 }, + { 48, 48, 48, 48, 80, 80, 80, 80 }, + { 32, 32, 32, 32, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 112, 112, 112, 112 } +}; + +unsigned int vp8_sub_pixel_variance4x4_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse) + +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil4x4_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 4)); +} + + +unsigned int vp8_sub_pixel_variance8x8_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 6)); +} + +unsigned int vp8_sub_pixel_variance16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 8)); + + +} + +unsigned int vp8_sub_pixel_mse16x16_mmx( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_mmx(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 7)); +} + +unsigned int vp8_sub_pixel_variance8x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + int *sse +) +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 7)); +} + +unsigned int vp8_i_variance16x16_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3, avg; + + + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_mmx(src_ptr + (source_stride >> 1), source_stride, ref_ptr + (recon_stride >> 1), recon_stride, &sse2, &sum2) ; + vp8_get8x8var_mmx(src_ptr + (source_stride >> 1) + 8, source_stride, ref_ptr + (recon_stride >> 1) + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + avg = sum0 + sum1 + sum2 + sum3; + *sse = var; + return (var - ((avg * avg) >> 8)); + +} + +unsigned int vp8_i_variance8x16_mmx( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + vp8_get8x8var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_mmx(src_ptr + (source_stride >> 1), source_stride, ref_ptr + (recon_stride >> 1), recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + + *sse = var; + return (var - ((avg * avg) >> 7)); + +} + +unsigned int vp8_i_sub_pixel_variance16x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + int f2soffset = (src_pixels_per_line >> 1); + int f2doffset = (dst_pixels_per_line >> 1); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + vp8_filter_block2d_bil_var_mmx( + src_ptr + f2soffset, src_pixels_per_line, + dst_ptr + f2doffset, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + vp8_filter_block2d_bil_var_mmx( + src_ptr + f2soffset + 8, src_pixels_per_line, + dst_ptr + f2doffset + 8, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 8)); +} + + +unsigned int vp8_i_sub_pixel_variance8x16_mmx +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + int f2soffset = (src_pixels_per_line >> 1); + int f2doffset = (dst_pixels_per_line >> 1); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_mmx( + src_ptr + f2soffset, src_pixels_per_line, + dst_ptr + f2doffset, dst_pixels_per_line, 8, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 7)); +}
diff --git a/vp8/encoder/x86/variance_sse2.c b/vp8/encoder/x86/variance_sse2.c new file mode 100644 index 0000000..ea80753 --- /dev/null +++ b/vp8/encoder/x86/variance_sse2.c
@@ -0,0 +1,514 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "variance.h" +#include "pragmas.h" +#include "vpx_ports/mem.h" + +extern void filter_block1d_h6_mmx(unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); +extern void filter_block1d_v6_mmx(short *src_ptr, unsigned char *output_ptr, unsigned int pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); +extern void filter_block1d8_h6_sse2(unsigned char *src_ptr, unsigned short *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); +extern void filter_block1d8_v6_sse2(short *src_ptr, unsigned char *output_ptr, unsigned int pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, short *vp7_filter); + +extern void vp8_filter_block2d_bil4x4_var_mmx +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); + +extern unsigned int vp8_get4x4var_mmx +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); + +unsigned int vp8_get_mb_ss_sse2 +( + short *src_ptr +); +unsigned int vp8_get16x16var_sse2 +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +unsigned int vp8_get16x16pred_error_sse2 +( + unsigned char *src_ptr, + int src_stride, + unsigned char *ref_ptr, + int ref_stride +); +unsigned int vp8_get8x8var_sse2 +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *SSE, + int *Sum +); +void vp8_filter_block2d_bil_var_sse2 +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + const short *HFilter, + const short *VFilter, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_vert_variance16x_h_sse2 +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_horiz_variance16x_h_sse2 +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); +void vp8_half_vert_variance16x_h_sse2 +( + unsigned char *ref_ptr, + int ref_pixels_per_line, + unsigned char *src_ptr, + int src_pixels_per_line, + unsigned int Height, + int *sum, + unsigned int *sumsquared +); + +DECLARE_ALIGNED(16, extern short, vp8_vp7_bilinear_filters_mmx[8][8]); + +unsigned int vp8_variance4x4_wmt( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride) +{ + unsigned int var; + int avg; + + vp8_get4x4var_mmx(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + return (var - ((avg * avg) >> 4)); + +} + + + +unsigned int vp8_variance8x8_wmt +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride) +{ + unsigned int var; + int avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &var, &avg) ; + + return (var - ((avg * avg) >> 6)); + +} + + +unsigned int vp8_variance16x16_wmt +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0; + int sum0; + + + vp8_get16x16var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + *sse = sse0; + return (sse0 - ((sum0 * sum0) >> 8)); +} +unsigned int vp8_mse16x16_wmt( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + + unsigned int sse0; + int sum0; + vp8_get16x16var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + *sse = sse0; + return sse0; + +} + + +unsigned int vp8_variance16x8_wmt +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((avg * avg) >> 7)); + +} + +unsigned int vp8_variance8x16_wmt +( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + 8 * source_stride, source_stride, ref_ptr + 8 * recon_stride, recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + *sse = var; + return (var - ((avg * avg) >> 7)); + +} + +/////////////////////////////////////////////////////////////////////////// +// the mmx function that does the bilinear filtering and var calculation // +// int one pass // +/////////////////////////////////////////////////////////////////////////// +DECLARE_ALIGNED(16, const short, vp8_bilinear_filters_xmm[8][16]) = +{ + { 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 112, 112, 112, 112, 112, 112, 112, 112, 16, 16, 16, 16, 16, 16, 16, 16 }, + { 96, 96, 96, 96, 96, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32 }, + { 80, 80, 80, 80, 80, 80, 80, 80, 48, 48, 48, 48, 48, 48, 48, 48 }, + { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }, + { 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80 }, + { 32, 32, 32, 32, 32, 32, 32, 32, 96, 96, 96, 96, 96, 96, 96, 96 }, + { 16, 16, 16, 16, 16, 16, 16, 16, 112, 112, 112, 112, 112, 112, 112, 112 } +}; +unsigned int vp8_sub_pixel_variance4x4_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil4x4_var_mmx( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, + vp8_vp7_bilinear_filters_mmx[xoffset], vp8_vp7_bilinear_filters_mmx[yoffset], + &xsum, &xxsum + ); + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 4)); +} + + +unsigned int vp8_sub_pixel_variance8x8_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum, &xxsum + ); + + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 6)); +} + +unsigned int vp8_sub_pixel_variance16x16_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + // note we could avoid these if statements if the calling function + // just called the appropriate functions inside. + if (xoffset == 4 && yoffset == 0) + { + vp8_half_horiz_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + vp8_half_horiz_variance16x_h_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + &xsum1, &xxsum1); + } + else if (xoffset == 0 && yoffset == 4) + { + vp8_half_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + vp8_half_vert_variance16x_h_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + &xsum1, &xxsum1); + } + else if (xoffset == 4 && yoffset == 4) + { + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + &xsum0, &xxsum0); + + vp8_half_horiz_vert_variance16x_h_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + &xsum1, &xxsum1); + } + else + { + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 16, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum1, &xxsum1 + ); + } + + xsum0 += xsum1; + xxsum0 += xxsum1; + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 8)); +} + +unsigned int vp8_sub_pixel_mse16x16_wmt( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + vp8_sub_pixel_variance16x16_wmt(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); + return *sse; +} + +unsigned int vp8_sub_pixel_variance16x8_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse + +) +{ + int xsum0, xsum1; + unsigned int xxsum0, xxsum1; + + + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 8, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum0, &xxsum0 + ); + + + vp8_filter_block2d_bil_var_sse2( + src_ptr + 8, src_pixels_per_line, + dst_ptr + 8, dst_pixels_per_line, 8, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum1, &xxsum1 + ); + + xsum0 += xsum1; + xxsum0 += xxsum1; + + *sse = xxsum0; + return (xxsum0 - ((xsum0 * xsum0) >> 7)); +} + +unsigned int vp8_sub_pixel_variance8x16_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + int xsum; + unsigned int xxsum; + vp8_filter_block2d_bil_var_sse2( + src_ptr, src_pixels_per_line, + dst_ptr, dst_pixels_per_line, 16, + vp8_bilinear_filters_xmm[xoffset], vp8_bilinear_filters_xmm[yoffset], + &xsum, &xxsum + ); + + *sse = xxsum; + return (xxsum - ((xsum * xsum) >> 7)); +} + +unsigned int vp8_i_variance16x16_wmt( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, sse2, sse3, var; + int sum0, sum1, sum2, sum3, avg; + + + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + 8, source_stride, ref_ptr + 8, recon_stride, &sse1, &sum1); + vp8_get8x8var_sse2(src_ptr + (source_stride >> 1), source_stride, ref_ptr + (recon_stride >> 1), recon_stride, &sse2, &sum2) ; + vp8_get8x8var_sse2(src_ptr + (source_stride >> 1) + 8, source_stride, ref_ptr + (recon_stride >> 1) + 8, recon_stride, &sse3, &sum3); + + var = sse0 + sse1 + sse2 + sse3; + avg = sum0 + sum1 + sum2 + sum3; + + *sse = var; + return (var - ((avg * avg) >> 8)); + +} + +unsigned int vp8_i_variance8x16_wmt( + unsigned char *src_ptr, + int source_stride, + unsigned char *ref_ptr, + int recon_stride, + unsigned int *sse) +{ + unsigned int sse0, sse1, var; + int sum0, sum1, avg; + vp8_get8x8var_sse2(src_ptr, source_stride, ref_ptr, recon_stride, &sse0, &sum0) ; + vp8_get8x8var_sse2(src_ptr + (source_stride >> 1), source_stride, ref_ptr + (recon_stride >> 1), recon_stride, &sse1, &sum1) ; + + var = sse0 + sse1; + avg = sum0 + sum1; + + *sse = var; + return (var - ((avg * avg) >> 7)); + +} + + +unsigned int vp8_i_sub_pixel_variance16x16_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + return vp8_sub_pixel_variance16x16_wmt(src_ptr, (src_pixels_per_line >> 1), xoffset, yoffset, dst_ptr, (dst_pixels_per_line >> 1), sse); +} + + +unsigned int vp8_i_sub_pixel_variance8x16_wmt +( + unsigned char *src_ptr, + int src_pixels_per_line, + int xoffset, + int yoffset, + unsigned char *dst_ptr, + int dst_pixels_per_line, + unsigned int *sse +) +{ + + return vp8_sub_pixel_variance8x16_wmt(src_ptr, (src_pixels_per_line >> 1), xoffset, yoffset, dst_ptr, (dst_pixels_per_line >> 1), sse); +}
diff --git a/vp8/encoder/x86/variance_x86.h b/vp8/encoder/x86/variance_x86.h new file mode 100644 index 0000000..35fc90c --- /dev/null +++ b/vp8/encoder/x86/variance_x86.h
@@ -0,0 +1,275 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#ifndef VARIANCE_X86_H +#define VARIANCE_X86_H + + +/* Note: + * + * This platform is commonly built for runtime CPU detection. If you modify + * any of the function mappings present in this file, be sure to also update + * them in the function pointer initialization code + */ +#if HAVE_MMX +extern prototype_sad(vp8_sad4x4_mmx); +extern prototype_sad(vp8_sad8x8_mmx); +extern prototype_sad(vp8_sad8x16_mmx); +extern prototype_sad(vp8_sad16x8_mmx); +extern prototype_sad(vp8_sad16x16_mmx); +extern prototype_variance(vp8_variance4x4_mmx); +extern prototype_variance(vp8_variance8x8_mmx); +extern prototype_variance(vp8_variance8x16_mmx); +extern prototype_variance(vp8_variance16x8_mmx); +extern prototype_variance(vp8_variance16x16_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_variance4x4_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_variance8x8_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_variance8x16_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_variance16x8_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_variance16x16_mmx); +extern prototype_subpixvariance(vp8_sub_pixel_mse16x16_mmx); +extern prototype_getmbss(vp8_get_mb_ss_mmx); +extern prototype_variance(vp8_mse16x16_mmx); +extern prototype_sad(vp8_get16x16pred_error_mmx); +extern prototype_variance2(vp8_get8x8var_mmx); +extern prototype_variance2(vp8_get16x16var_mmx); +extern prototype_sad(vp8_get4x4sse_cs_mmx); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_variance_sad4x4 +#define vp8_variance_sad4x4 vp8_sad4x4_mmx + +#undef vp8_variance_sad8x8 +#define vp8_variance_sad8x8 vp8_sad8x8_mmx + +#undef vp8_variance_sad8x16 +#define vp8_variance_sad8x16 vp8_sad8x16_mmx + +#undef vp8_variance_sad16x8 +#define vp8_variance_sad16x8 vp8_sad16x8_mmx + +#undef vp8_variance_sad16x16 +#define vp8_variance_sad16x16 vp8_sad16x16_mmx + +#undef vp8_variance_var4x4 +#define vp8_variance_var4x4 vp8_variance4x4_mmx + +#undef vp8_variance_var8x8 +#define vp8_variance_var8x8 vp8_variance8x8_mmx + +#undef vp8_variance_var8x16 +#define vp8_variance_var8x16 vp8_variance8x16_mmx + +#undef vp8_variance_var16x8 +#define vp8_variance_var16x8 vp8_variance16x8_mmx + +#undef vp8_variance_var16x16 +#define vp8_variance_var16x16 vp8_variance16x16_mmx + +#undef vp8_variance_subpixvar4x4 +#define vp8_variance_subpixvar4x4 vp8_sub_pixel_variance4x4_mmx + +#undef vp8_variance_subpixvar8x8 +#define vp8_variance_subpixvar8x8 vp8_sub_pixel_variance8x8_mmx + +#undef vp8_variance_subpixvar8x16 +#define vp8_variance_subpixvar8x16 vp8_sub_pixel_variance8x16_mmx + +#undef vp8_variance_subpixvar16x8 +#define vp8_variance_subpixvar16x8 vp8_sub_pixel_variance16x8_mmx + +#undef vp8_variance_subpixvar16x16 +#define vp8_variance_subpixvar16x16 vp8_sub_pixel_variance16x16_mmx + +#undef vp8_variance_subpixmse16x16 +#define vp8_variance_subpixmse16x16 vp8_sub_pixel_mse16x16_mmx + +#undef vp8_variance_getmbss +#define vp8_variance_getmbss vp8_get_mb_ss_mmx + +#undef vp8_variance_mse16x16 +#define vp8_variance_mse16x16 vp8_mse16x16_mmx + +#undef vp8_variance_get16x16prederror +#define vp8_variance_get16x16prederror vp8_get16x16pred_error_mmx + +#undef vp8_variance_get8x8var +#define vp8_variance_get8x8var vp8_get8x8var_mmx + +#undef vp8_variance_get16x16var +#define vp8_variance_get16x16var vp8_get16x16var_mmx + +#undef vp8_variance_get4x4sse_cs +#define vp8_variance_get4x4sse_cs vp8_get4x4sse_cs_mmx + +#endif +#endif + + +#if HAVE_SSE2 +extern prototype_sad(vp8_sad4x4_wmt); +extern prototype_sad(vp8_sad8x8_wmt); +extern prototype_sad(vp8_sad8x16_wmt); +extern prototype_sad(vp8_sad16x8_wmt); +extern prototype_sad(vp8_sad16x16_wmt); +extern prototype_variance(vp8_variance4x4_wmt); +extern prototype_variance(vp8_variance8x8_wmt); +extern prototype_variance(vp8_variance8x16_wmt); +extern prototype_variance(vp8_variance16x8_wmt); +extern prototype_variance(vp8_variance16x16_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_variance4x4_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_variance8x8_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_variance8x16_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_variance16x8_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_variance16x16_wmt); +extern prototype_subpixvariance(vp8_sub_pixel_mse16x16_wmt); +extern prototype_getmbss(vp8_get_mb_ss_sse2); +extern prototype_variance(vp8_mse16x16_wmt); +extern prototype_sad(vp8_get16x16pred_error_sse2); +extern prototype_variance2(vp8_get8x8var_sse2); +extern prototype_variance2(vp8_get16x16var_sse2); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_variance_sad4x4 +#define vp8_variance_sad4x4 vp8_sad4x4_wmt + +#undef vp8_variance_sad8x8 +#define vp8_variance_sad8x8 vp8_sad8x8_wmt + +#undef vp8_variance_sad8x16 +#define vp8_variance_sad8x16 vp8_sad8x16_wmt + +#undef vp8_variance_sad16x8 +#define vp8_variance_sad16x8 vp8_sad16x8_wmt + +#undef vp8_variance_sad16x16 +#define vp8_variance_sad16x16 vp8_sad16x16_wmt + +#undef vp8_variance_var4x4 +#define vp8_variance_var4x4 vp8_variance4x4_wmt + +#undef vp8_variance_var8x8 +#define vp8_variance_var8x8 vp8_variance8x8_wmt + +#undef vp8_variance_var8x16 +#define vp8_variance_var8x16 vp8_variance8x16_wmt + +#undef vp8_variance_var16x8 +#define vp8_variance_var16x8 vp8_variance16x8_wmt + +#undef vp8_variance_var16x16 +#define vp8_variance_var16x16 vp8_variance16x16_wmt + +#undef vp8_variance_subpixvar4x4 +#define vp8_variance_subpixvar4x4 vp8_sub_pixel_variance4x4_wmt + +#undef vp8_variance_subpixvar8x8 +#define vp8_variance_subpixvar8x8 vp8_sub_pixel_variance8x8_wmt + +#undef vp8_variance_subpixvar8x16 +#define vp8_variance_subpixvar8x16 vp8_sub_pixel_variance8x16_wmt + +#undef vp8_variance_subpixvar16x8 +#define vp8_variance_subpixvar16x8 vp8_sub_pixel_variance16x8_wmt + +#undef vp8_variance_subpixvar16x16 +#define vp8_variance_subpixvar16x16 vp8_sub_pixel_variance16x16_wmt + +#undef vp8_variance_subpixmse16x16 +#define vp8_variance_subpixmse16x16 vp8_sub_pixel_mse16x16_wmt + +#undef vp8_variance_getmbss +#define vp8_variance_getmbss vp8_get_mb_ss_sse2 + +#undef vp8_variance_mse16x16 +#define vp8_variance_mse16x16 vp8_mse16x16_wmt + +#undef vp8_variance_get16x16prederror +#define vp8_variance_get16x16prederror vp8_get16x16pred_error_sse2 + +#undef vp8_variance_get8x8var +#define vp8_variance_get8x8var vp8_get8x8var_sse2 + +#undef vp8_variance_get16x16var +#define vp8_variance_get16x16var vp8_get16x16var_sse2 + +#endif +#endif + + +#if HAVE_SSE3 +extern prototype_sad(vp8_sad16x16_sse3); +extern prototype_sad(vp8_sad16x8_sse3); +extern prototype_sad_multi_same_address(vp8_sad16x16x3_sse3); +extern prototype_sad_multi_same_address(vp8_sad16x8x3_sse3); +extern prototype_sad_multi_same_address(vp8_sad8x16x3_sse3); +extern prototype_sad_multi_same_address(vp8_sad8x8x3_sse3); +extern prototype_sad_multi_same_address(vp8_sad4x4x3_sse3); + +extern prototype_sad_multi_dif_address(vp8_sad16x16x4d_sse3); +extern prototype_sad_multi_dif_address(vp8_sad16x8x4d_sse3); +extern prototype_sad_multi_dif_address(vp8_sad8x16x4d_sse3); +extern prototype_sad_multi_dif_address(vp8_sad8x8x4d_sse3); +extern prototype_sad_multi_dif_address(vp8_sad4x4x4d_sse3); + +#if !CONFIG_RUNTIME_CPU_DETECT + +#undef vp8_variance_sad16x16 +#define vp8_variance_sad16x16 vp8_sad16x16_sse3 + +#undef vp8_variance_sad16x16x3 +#define vp8_variance_sad16x16x3 vp8_sad16x16x3_sse3 + +#undef vp8_variance_sad16x8x3 +#define vp8_variance_sad16x8x3 vp8_sad16x8x3_sse3 + +#undef vp8_variance_sad8x16x3 +#define vp8_variance_sad8x16x3 vp8_sad8x16x3_sse3 + +#undef vp8_variance_sad8x8x3 +#define vp8_variance_sad8x8x3 vp8_sad8x8x3_sse3 + +#undef vp8_variance_sad4x4x3 +#define vp8_variance_sad4x4x3 vp8_sad4x4x3_sse3 + +#undef vp8_variance_sad16x16x4d +#define vp8_variance_sad16x16x4 vp8_sad16x16x4d_sse3 + +#undef vp8_variance_sad16x8x4d +#define vp8_variance_sad16x8x4d vp8_sad16x8x4d_sse3 + +#undef vp8_variance_sad8x16x4d +#define vp8_variance_sad8x16x4d vp8_sad8x16x4d_sse3 + +#undef vp8_variance_sad8x8x4d +#define vp8_variance_sad8x8x4d vp8_sad8x8x4d_sse3 + +#undef vp8_variance_sad4x4x4d +#define vp8_variance_sad4x4x4d vp8_sad4x4x4d_sse3 + +#endif +#endif + + +#if HAVE_SSSE3 +extern prototype_sad_multi_same_address(vp8_sad16x16x3_ssse3); +extern prototype_sad_multi_same_address(vp8_sad16x8x3_ssse3); + +#if !CONFIG_RUNTIME_CPU_DETECT +#undef vp8_variance_sad16x16x3 +#define vp8_variance_sad16x16x3 vp8_sad16x16x3_ssse3 + +#undef vp8_variance_sad16x8x3 +#define vp8_variance_sad16x8x3 vp8_sad16x8x3_ssse3 + +#endif +#endif + +#endif
diff --git a/vp8/encoder/x86/x86_csystemdependent.c b/vp8/encoder/x86/x86_csystemdependent.c new file mode 100644 index 0000000..f1391ba --- /dev/null +++ b/vp8/encoder/x86/x86_csystemdependent.c
@@ -0,0 +1,287 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_ports/config.h" +#include "vpx_ports/x86.h" +#include "variance.h" +#include "onyx_int.h" + + +#if HAVE_MMX +void vp8_short_fdct8x4_mmx(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_mmx(input, output, pitch); + vp8_short_fdct4x4_mmx(input + 4, output + 16, pitch); +} + +void vp8_fast_fdct8x4_mmx(short *input, short *output, int pitch) +{ + vp8_fast_fdct4x4_mmx(input, output , pitch); + vp8_fast_fdct4x4_mmx(input + 4, output + 16, pitch); +} + +int vp8_fast_quantize_b_impl_mmx(short *coeff_ptr, short *zbin_ptr, + short *qcoeff_ptr, short *dequant_ptr, + short *scan_mask, short *round_ptr, + short *quant_ptr, short *dqcoeff_ptr); +void vp8_fast_quantize_b_mmx(BLOCK *b, BLOCKD *d) +{ + short *scan_mask = vp8_default_zig_zag_mask;//d->scan_order_mask_ptr; + short *coeff_ptr = &b->coeff[0]; + short *zbin_ptr = &b->zbin[0][0]; + short *round_ptr = &b->round[0][0]; + short *quant_ptr = &b->quant[0][0]; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = &d->dequant[0][0]; + + d->eob = vp8_fast_quantize_b_impl_mmx( + coeff_ptr, + zbin_ptr, + qcoeff_ptr, + dequant_ptr, + scan_mask, + + round_ptr, + quant_ptr, + dqcoeff_ptr + ); +} + +int vp8_mbblock_error_mmx_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +int vp8_mbblock_error_mmx(MACROBLOCK *mb, int dc) +{ + short *coeff_ptr = mb->block[0].coeff; + short *dcoef_ptr = mb->e_mbd.block[0].dqcoeff; + return vp8_mbblock_error_mmx_impl(coeff_ptr, dcoef_ptr, dc); +} + +int vp8_mbuverror_mmx_impl(short *s_ptr, short *d_ptr); +int vp8_mbuverror_mmx(MACROBLOCK *mb) +{ + short *s_ptr = &mb->coeff[256]; + short *d_ptr = &mb->e_mbd.dqcoeff[256]; + return vp8_mbuverror_mmx_impl(s_ptr, d_ptr); +} + +void vp8_subtract_b_mmx_impl(unsigned char *z, int src_stride, + short *diff, unsigned char *predictor, + int pitch); +void vp8_subtract_b_mmx(BLOCK *be, BLOCKD *bd, int pitch) +{ + unsigned char *z = *(be->base_src) + be->src; + unsigned int src_stride = be->src_stride; + short *diff = &be->src_diff[0]; + unsigned char *predictor = &bd->predictor[0]; + vp8_subtract_b_mmx_impl(z, src_stride, diff, predictor, pitch); +} + +#endif + +#if HAVE_SSE2 +void vp8_short_fdct8x4_wmt(short *input, short *output, int pitch) +{ + vp8_short_fdct4x4_wmt(input, output, pitch); + vp8_short_fdct4x4_wmt(input + 4, output + 16, pitch); +} + +int vp8_fast_quantize_b_impl_sse(short *coeff_ptr, short *zbin_ptr, + short *qcoeff_ptr, short *dequant_ptr, + short *scan_mask, short *round_ptr, + short *quant_ptr, short *dqcoeff_ptr); +void vp8_fast_quantize_b_sse(BLOCK *b, BLOCKD *d) +{ + short *scan_mask = vp8_default_zig_zag_mask;//d->scan_order_mask_ptr; + short *coeff_ptr = &b->coeff[0]; + short *zbin_ptr = &b->zbin[0][0]; + short *round_ptr = &b->round[0][0]; + short *quant_ptr = &b->quant[0][0]; + short *qcoeff_ptr = d->qcoeff; + short *dqcoeff_ptr = d->dqcoeff; + short *dequant_ptr = &d->dequant[0][0]; + + d->eob = vp8_fast_quantize_b_impl_sse( + coeff_ptr, + zbin_ptr, + qcoeff_ptr, + dequant_ptr, + scan_mask, + + round_ptr, + quant_ptr, + dqcoeff_ptr + ); +} + +int vp8_mbblock_error_xmm_impl(short *coeff_ptr, short *dcoef_ptr, int dc); +int vp8_mbblock_error_xmm(MACROBLOCK *mb, int dc) +{ + short *coeff_ptr = mb->block[0].coeff; + short *dcoef_ptr = mb->e_mbd.block[0].dqcoeff; + return vp8_mbblock_error_xmm_impl(coeff_ptr, dcoef_ptr, dc); +} + +int vp8_mbuverror_xmm_impl(short *s_ptr, short *d_ptr); +int vp8_mbuverror_xmm(MACROBLOCK *mb) +{ + short *s_ptr = &mb->coeff[256]; + short *d_ptr = &mb->e_mbd.dqcoeff[256]; + return vp8_mbuverror_xmm_impl(s_ptr, d_ptr); +} + +#endif + +void vp8_arch_x86_encoder_init(VP8_COMP *cpi) +{ +#if CONFIG_RUNTIME_CPU_DETECT + int flags = x86_simd_caps(); + int mmx_enabled = flags & HAS_MMX; + int xmm_enabled = flags & HAS_SSE; + int wmt_enabled = flags & HAS_SSE2; + int SSE3Enabled = flags & HAS_SSE3; + int SSSE3Enabled = flags & HAS_SSSE3; + + /* Note: + * + * This platform can be built without runtime CPU detection as well. If + * you modify any of the function mappings present in this file, be sure + * to also update them in static mapings (<arch>/filename_<arch>.h) + */ + + /* Override default functions with fastest ones for this CPU. */ +#if HAVE_MMX + + if (mmx_enabled) + { + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_mmx; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_mmx; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_mmx; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_mmx; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_mmx; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_mmx; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_mmx; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_mmx; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_mmx; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_mmx; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_mmx; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_mmx; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_mmx; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_mmx; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_mmx; + cpi->rtcd.variance.subpixmse16x16 = vp8_sub_pixel_mse16x16_mmx; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_mmx; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_mmx; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_mmx; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_mmx; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_mmx; + cpi->rtcd.variance.get4x4sse_cs = vp8_get4x4sse_cs_mmx; + + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_mmx; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_mmx; + cpi->rtcd.fdct.fast4x4 = vp8_fast_fdct4x4_mmx; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_mmx; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_c; + + cpi->rtcd.encodemb.berr = vp8_block_error_mmx; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_mmx; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_mmx; + cpi->rtcd.encodemb.subb = vp8_subtract_b_mmx; + cpi->rtcd.encodemb.submby = vp8_subtract_mby_mmx; + cpi->rtcd.encodemb.submbuv = vp8_subtract_mbuv_mmx; + + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_mmx; + } + +#endif +#if HAVE_SSE2 + + if (wmt_enabled) + { + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_wmt; + cpi->rtcd.variance.sad16x8 = vp8_sad16x8_wmt; + cpi->rtcd.variance.sad8x16 = vp8_sad8x16_wmt; + cpi->rtcd.variance.sad8x8 = vp8_sad8x8_wmt; + cpi->rtcd.variance.sad4x4 = vp8_sad4x4_wmt; + + cpi->rtcd.variance.var4x4 = vp8_variance4x4_wmt; + cpi->rtcd.variance.var8x8 = vp8_variance8x8_wmt; + cpi->rtcd.variance.var8x16 = vp8_variance8x16_wmt; + cpi->rtcd.variance.var16x8 = vp8_variance16x8_wmt; + cpi->rtcd.variance.var16x16 = vp8_variance16x16_wmt; + + cpi->rtcd.variance.subpixvar4x4 = vp8_sub_pixel_variance4x4_wmt; + cpi->rtcd.variance.subpixvar8x8 = vp8_sub_pixel_variance8x8_wmt; + cpi->rtcd.variance.subpixvar8x16 = vp8_sub_pixel_variance8x16_wmt; + cpi->rtcd.variance.subpixvar16x8 = vp8_sub_pixel_variance16x8_wmt; + cpi->rtcd.variance.subpixvar16x16 = vp8_sub_pixel_variance16x16_wmt; + cpi->rtcd.variance.subpixmse16x16 = vp8_sub_pixel_mse16x16_wmt; + + cpi->rtcd.variance.mse16x16 = vp8_mse16x16_wmt; + cpi->rtcd.variance.getmbss = vp8_get_mb_ss_sse2; + + cpi->rtcd.variance.get16x16prederror = vp8_get16x16pred_error_sse2; + cpi->rtcd.variance.get8x8var = vp8_get8x8var_sse2; + cpi->rtcd.variance.get16x16var = vp8_get16x16var_sse2; + /* cpi->rtcd.variance.get4x4sse_cs not implemented for wmt */; + +#if 0 + /* short SSE2 DCT currently disabled, does not match the MMX version */ + cpi->rtcd.fdct.short4x4 = vp8_short_fdct4x4_wmt; + cpi->rtcd.fdct.short8x4 = vp8_short_fdct8x4_wmt; +#endif + /* cpi->rtcd.fdct.fast4x4 not implemented for wmt */; + cpi->rtcd.fdct.fast8x4 = vp8_fast_fdct8x4_wmt; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_sse2; + + cpi->rtcd.encodemb.berr = vp8_block_error_xmm; + cpi->rtcd.encodemb.mberr = vp8_mbblock_error_xmm; + cpi->rtcd.encodemb.mbuverr = vp8_mbuverror_xmm; + /* cpi->rtcd.encodemb.sub* not implemented for wmt */ + + cpi->rtcd.quantize.fastquantb = vp8_fast_quantize_b_sse; + } + +#endif +#if HAVE_SSE3 + + if (SSE3Enabled) + { + cpi->rtcd.variance.sad16x16 = vp8_sad16x16_sse3; + cpi->rtcd.variance.sad16x16x3 = vp8_sad16x16x3_sse3; + cpi->rtcd.variance.sad16x8x3 = vp8_sad16x8x3_sse3; + cpi->rtcd.variance.sad8x16x3 = vp8_sad8x16x3_sse3; + cpi->rtcd.variance.sad8x8x3 = vp8_sad8x8x3_sse3; + cpi->rtcd.variance.sad4x4x3 = vp8_sad4x4x3_sse3; + cpi->rtcd.search.full_search = vp8_full_search_sadx3; + + cpi->rtcd.variance.sad16x16x4d = vp8_sad16x16x4d_sse3; + cpi->rtcd.variance.sad16x8x4d = vp8_sad16x8x4d_sse3; + cpi->rtcd.variance.sad8x16x4d = vp8_sad8x16x4d_sse3; + cpi->rtcd.variance.sad8x8x4d = vp8_sad8x8x4d_sse3; + cpi->rtcd.variance.sad4x4x4d = vp8_sad4x4x4d_sse3; + cpi->rtcd.search.diamond_search = vp8_diamond_search_sadx4; + } + +#endif +#if HAVE_SSSE3 + + if (SSSE3Enabled) + { + cpi->rtcd.variance.sad16x16x3 = vp8_sad16x16x3_ssse3; + cpi->rtcd.variance.sad16x8x3 = vp8_sad16x8x3_ssse3; + } + +#endif +#endif +}
diff --git a/vp8/vp8.h b/vp8/vp8.h new file mode 100644 index 0000000..87ca217 --- /dev/null +++ b/vp8/vp8.h
@@ -0,0 +1,116 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/*!\defgroup vp8 VP8 + * \ingroup codecs + * VP8 is vpx's newest video compression algorithm that uses motion + * compensated prediction, Discrete Cosine Transform (DCT) coding of the + * prediction error signal and context dependent entropy coding techniques + * based on arithmatic principles. It features: + * - YUV 4:2:0 image format + * - Macro-block based coding (16x16 luma plus two 8x8 chroma) + * - 1/4 (1/8) pixel accuracy motion compensated prediction + * - 4x4 DCT transform + * - 128 level linear quantizer + * - In loop deblocking filter + * - Context-based entropy coding + * + * @{ + */ +/*!\file vp8.h + * \brief Provides controls common to both the VP8 encoder and decoder. + */ +#ifndef VP8_H +#define VP8_H +#include "vpx_codec_impl_top.h" + +/*!\brief Control functions + * + * The set of macros define the control functions of VP8 interface + */ +enum vp8_dec_control_id +{ + VP8_SET_REFERENCE = 1, /**< pass in an external frame into decoder to be used as reference frame */ + VP8_COPY_REFERENCE = 2, /**< get a copy of reference frame from the decoder */ + VP8_SET_POSTPROC = 3, /**< set decoder's the post processing settings */ + VP8_COMMON_CTRL_ID_MAX +}; + +/*!\brief post process flags + * + * The set of macros define VP8 decoder post processing flags + */ +enum vp8_postproc_level +{ + VP8_NOFILTERING = 0, + VP8_DEBLOCK = 1, + VP8_DEMACROBLOCK = 2, + VP8_ADDNOISE = 4, +}; + +/*!\brief post process flags + * + * This define a structure that describe the post processing settings. For + * the best objective measure (using thet PSNR metric) set post_proc_flag + * to VP8_DEBLOCK and deblocking_level to 1. + */ + +typedef struct vp8_postproc_cfg +{ + int post_proc_flag; /**< the types of post processing to be done, should be combination of "vp8_postproc_level" */ + int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */ + int noise_level; /**< the strength of additive noise, valid range [0, 16] */ +} vp8_postproc_cfg_t; + +/*!\brief reference frame type + * + * The set of macros define the type of VP8 reference frames + */ +typedef enum vpx_ref_frame_type +{ + VP8_LAST_FRAME = 1, + VP8_GOLD_FRAME = 2, + VP8_ALTR_FRAME = 4 +} vpx_ref_frame_type_t; + +/*!\brief reference frame data struct + * + * define the data struct to access vp8 reference frames + */ + +typedef struct vpx_ref_frame +{ + vpx_ref_frame_type_t frame_type; /**< which reference frame */ + vpx_image_t img; /**< reference frame data in image format */ +} vpx_ref_frame_t; + + +/*!\brief vp8 decoder control funciton parameter type + * + * defines the data type for each of VP8 decoder control funciton requires + */ + +VPX_CTRL_USE_TYPE(VP8_SET_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE(VP8_COPY_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE(VP8_SET_POSTPROC, vp8_postproc_cfg_t *) + + +/*! @} - end defgroup vp8 */ + +#if !defined(VPX_CODEC_DISABLE_COMPAT) || !VPX_CODEC_DISABLE_COMPAT +/* The following definitions are provided for backward compatibility with + * the VP8 1.0.x SDK. USE IN PRODUCTION CODE IS NOT RECOMMENDED. + */ + +DECLSPEC_DEPRECATED extern vpx_codec_iface_t vpx_codec_vp8_algo DEPRECATED; +#endif + +#include "vpx_codec_impl_bottom.h" +#endif
diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk new file mode 100644 index 0000000..ec467c5 --- /dev/null +++ b/vp8/vp8_common.mk
@@ -0,0 +1,190 @@ +## +## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license and patent +## grant that can be found in the LICENSE file in the root of the source +## tree. All contributing project authors may be found in the AUTHORS +## file in the root of the source tree. +## + + +#add this file to the installed sources list +VP8_COMMON_SRCS-yes += vp8_common.mk + +#common interface +VP8_COMMON_SRCS-yes += vp8.h + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)common +VP8_COMMON_SRCS-yes += common/type_aliases.h +VP8_COMMON_SRCS-yes += common/pragmas.h + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)common +VP8_COMMON_SRCS-yes += common/preproc.h +VP8_COMMON_SRCS-yes += common/vpxerrors.h + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)common +VP8_COMMON_SRCS-yes += common/ppflags.h +VP8_COMMON_SRCS-yes += common/onyx.h +VP8_COMMON_SRCS-yes += common/onyxd.h + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)common + +VP8_COMMON_SRCS-yes += common/segmentation_common.c +VP8_COMMON_SRCS-yes += common/alloccommon.c +VP8_COMMON_SRCS-yes += common/blockd.c +VP8_COMMON_SRCS-yes += common/coefupdateprobs.h +VP8_COMMON_SRCS-yes += common/debugmodes.c +VP8_COMMON_SRCS-yes += common/defaultcoefcounts.h +VP8_COMMON_SRCS-yes += common/entropy.c +VP8_COMMON_SRCS-yes += common/entropymode.c +VP8_COMMON_SRCS-yes += common/entropymv.c +VP8_COMMON_SRCS-yes += common/extend.c +VP8_COMMON_SRCS-yes += common/filter_c.c +VP8_COMMON_SRCS-yes += common/findnearmv.c +VP8_COMMON_SRCS-yes += common/generic/systemdependent.c +VP8_COMMON_SRCS-yes += common/idctllm.c +VP8_COMMON_SRCS-yes += common/alloccommon.h +VP8_COMMON_SRCS-yes += common/blockd.h +VP8_COMMON_SRCS-yes += common/common.h +VP8_COMMON_SRCS-yes += common/common_types.h +VP8_COMMON_SRCS-yes += common/entropy.h +VP8_COMMON_SRCS-yes += common/entropymode.h +VP8_COMMON_SRCS-yes += common/entropymv.h +VP8_COMMON_SRCS-yes += common/extend.h +VP8_COMMON_SRCS-yes += common/findnearmv.h +VP8_COMMON_SRCS-yes += common/g_common.h +VP8_COMMON_SRCS-yes += common/header.h +VP8_COMMON_SRCS-yes += common/idct.h +VP8_COMMON_SRCS-yes += common/invtrans.h +VP8_COMMON_SRCS-yes += common/loopfilter.h +VP8_COMMON_SRCS-yes += common/modecont.h +VP8_COMMON_SRCS-yes += common/mv.h +VP8_COMMON_SRCS-yes += common/onyxc_int.h +VP8_COMMON_SRCS-yes += common/predictdc.h +VP8_COMMON_SRCS-yes += common/quant_common.h +VP8_COMMON_SRCS-yes += common/recon.h +VP8_COMMON_SRCS-yes += common/reconinter.h +VP8_COMMON_SRCS-yes += common/reconintra.h +VP8_COMMON_SRCS-yes += common/reconintra4x4.h +VP8_COMMON_SRCS-yes += common/segmentation_common.h +VP8_COMMON_SRCS-yes += common/setupintrarecon.h +VP8_COMMON_SRCS-yes += common/subpixel.h +VP8_COMMON_SRCS-yes += common/swapyv12buffer.h +VP8_COMMON_SRCS-yes += common/systemdependent.h +VP8_COMMON_SRCS-yes += common/threading.h +VP8_COMMON_SRCS-yes += common/treecoder.h +VP8_COMMON_SRCS-yes += common/invtrans.c +VP8_COMMON_SRCS-yes += common/loopfilter.c +VP8_COMMON_SRCS-yes += common/loopfilter_filters.c +VP8_COMMON_SRCS-yes += common/mbpitch.c +VP8_COMMON_SRCS-yes += common/modecont.c +VP8_COMMON_SRCS-yes += common/modecontext.c +VP8_COMMON_SRCS-yes += common/predictdc.c +VP8_COMMON_SRCS-yes += common/quant_common.c +VP8_COMMON_SRCS-yes += common/recon.c +VP8_COMMON_SRCS-yes += common/reconinter.c +VP8_COMMON_SRCS-yes += common/reconintra.c +VP8_COMMON_SRCS-yes += common/reconintra4x4.c +VP8_COMMON_SRCS-yes += common/setupintrarecon.c +VP8_COMMON_SRCS-yes += common/swapyv12buffer.c +VP8_COMMON_SRCS-yes += common/textblit.c +VP8_COMMON_SRCS-yes += common/treecoder.c + +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/idct_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/subpixel_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/recon_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/loopfilter_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/postproc_x86.h +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/x86_systemdependent.c +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/vp8_asm_stubs.c +VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/loopfilter_x86.c +VP8_COMMON_SRCS-$(CONFIG_POSTPROC) += common/postproc.h +VP8_COMMON_SRCS-$(CONFIG_POSTPROC) += common/postproc.c +VP8_COMMON_SRCS-$(CONFIG_VP8_ENCODER) += common/postproc.h +VP8_COMMON_SRCS-$(CONFIG_VP8_ENCODER) += common/postproc.c +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idctllm_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/iwalsh_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/recon_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/subpixel_mmx.asm +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/loopfilter_mmx.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/recon_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/subpixel_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/loopfilter_sse2.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/iwalsh_sse2.asm +ifeq ($(CONFIG_POSTPROC),yes) +VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/postproc_mmx.asm +VP8_COMMON_SRCS-$(HAVE_SSE2) += common/x86/postproc_sse2.asm +endif + +# common (c) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/bilinearfilter_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/filter_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/loopfilter_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/recon_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/reconintra4x4_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/reconintra_arm.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/systemdependent.c +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/vpx_asm_offsets.c + +VP8_COMMON_SRCS_REMOVE-$(HAVE_ARMV6) += common/filter_c.c +VP8_COMMON_SRCS_REMOVE-$(HAVE_ARMV6) += common/recon.c +VP8_COMMON_SRCS_REMOVE-$(HAVE_ARMV6) += common/reconintra4x4.c +VP8_COMMON_SRCS_REMOVE-$(HAVE_ARMV6) += common/generic/systemdependent.c + +# common (armv6) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/bilinearfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/copymem8x4_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/copymem8x8_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/copymem16x16_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/iwalsh_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/filter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/idct_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/loopfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/recon_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/simpleloopfilter_v6$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV6) += common/arm/armv6/sixtappredict8x4_v6$(ASM) + +# common (neon) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/bilinearpredict4x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/bilinearpredict8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/bilinearpredict8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/bilinearpredict16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/copymem8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/copymem8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/copymem16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/iwalsh_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfiltersimplehorizontaledge_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfiltersimpleverticaledge_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfilterhorizontaledge_uv_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfilterhorizontaledge_y_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfilterverticaledge_uv_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/loopfilterverticaledge_y_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/mbloopfilterhorizontaledge_uv_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/mbloopfilterhorizontaledge_y_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/mbloopfilterverticaledge_uv_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/mbloopfilterverticaledge_y_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/recon2b_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/recon4b_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/reconb_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/shortidct4x4llm_1_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/shortidct4x4llm_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/sixtappredict4x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/sixtappredict8x4_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/sixtappredict8x8_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/sixtappredict16x16_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/recon16x16mb_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/buildintrapredictorsmby_neon$(ASM) +VP8_COMMON_SRCS-$(HAVE_ARMV7) += common/arm/neon/save_neon_reg$(ASM) + + +# +# Rule to extract assembly constants from C sources +# +ifeq ($(ARCH_ARM),yes) +vpx_asm_offsets.asm: obj_int_extract +vpx_asm_offsets.asm: $(VP8_PREFIX)common/arm/vpx_asm_offsets.c.o + ./obj_int_extract rvds $< $(ADS2GAS) > $@ +OBJS-yes += $(VP8_PREFIX)common/arm/vpx_asm_offsets.c.o +CLEAN-OBJS += vpx_asm_offsets.asm +$(filter %$(ASM).o,$(OBJS-yes)): vpx_asm_offsets.asm +endif
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c new file mode 100644 index 0000000..e129ec9 --- /dev/null +++ b/vp8/vp8_cx_iface.c
@@ -0,0 +1,1177 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vpx_codec/vpx_codec.h" +#include "vpx_codec/internal/vpx_codec_internal.h" +#include "vpx_version.h" +#include "onyx_int.h" +#include "vp8e.h" +#include "onyx.h" +#include <stdlib.h> +#include <string.h> + +/* This value is a sentinel for determining whether the user has set a mode + * directly through the deprecated VP8E_SET_ENCODING_MODE control. + */ +#define NO_MODE_SET 255 + +struct vp8_extracfg +{ + struct vpx_codec_pkt_list *pkt_list; + vp8e_encoding_mode encoding_mode; /** best, good, realtime */ + int cpu_used; /** available cpu percentage in 1/16*/ + unsigned int enable_auto_alt_ref; /** if encoder decides to uses alternate reference frame */ + unsigned int noise_sensitivity; + unsigned int Sharpness; + unsigned int static_thresh; + unsigned int token_partitions; + unsigned int arnr_max_frames; /* alt_ref Noise Reduction Max Frame Count */ + unsigned int arnr_strength; /* alt_ref Noise Reduction Strength */ + unsigned int arnr_type; /* alt_ref filter type */ + +}; + +struct extraconfig_map +{ + int usage; + struct vp8_extracfg cfg; +}; + +static const struct extraconfig_map extracfg_map[] = +{ + { + 0, + { + NULL, +#if !(CONFIG_REALTIME_ONLY) + VP8_BEST_QUALITY_ENCODING, /* Encoding Mode */ + -4, /* cpu_used */ +#else + VP8_REAL_TIME_ENCODING, /* Encoding Mode */ + -8, /* cpu_used */ +#endif + 0, /* enable_auto_alt_ref */ + 0, /* noise_sensitivity */ + 0, /* Sharpness */ + 800, /* static_thresh */ + VP8_ONE_TOKENPARTITION, /* token_partitions */ + 0, /* arnr_max_frames */ + 0, /* arnr_strength */ + 0, /* arnr_type*/ + } + } +}; + +struct vpx_codec_alg_priv +{ + vpx_codec_priv_t base; + vpx_codec_enc_cfg_t cfg; + struct vp8_extracfg vp8_cfg; + VP8_CONFIG oxcf; + VP8_PTR cpi; + unsigned char *cx_data; + unsigned int cx_data_sz; + vpx_image_t preview_img; + unsigned int next_frame_flag; + vp8_postproc_cfg_t preview_ppcfg; + vpx_codec_pkt_list_decl(26) pkt_list; // changed to accomendate the maximum number of lagged frames allowed + int deprecated_mode; + unsigned int fixed_kf_cntr; +}; + + +static vpx_codec_err_t +update_error_state(vpx_codec_alg_priv_t *ctx, + const struct vpx_internal_error_info *error) +{ + vpx_codec_err_t res; + + if ((res = error->error_code)) + ctx->base.err_detail = error->has_detail + ? error->detail + : NULL; + + return res; +} + + +#define ERROR(str) do {\ + ctx->base.err_detail = str;\ + return VPX_CODEC_INVALID_PARAM;\ + } while(0) + +#define RANGE_CHECK(p,memb,lo,hi) do {\ + if(!((p)->memb >= (lo) && (p)->memb <= hi)) \ + ERROR(#memb " out of range ["#lo".."#hi"]");\ + } while(0) + +#define RANGE_CHECK_LO(p,memb,lo) do {\ + if(!((p)->memb >= (lo))) \ + ERROR(#memb " out of range ["#lo"..]");\ + } while(0) + +#define RANGE_CHECK_BOOL(p,memb) do {\ + if(!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean");\ + } while(0) + +static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, + const vpx_codec_enc_cfg_t *cfg, + const struct vp8_extracfg *vp8_cfg) +{ + RANGE_CHECK(cfg, g_w, 2, 16384); + RANGE_CHECK(cfg, g_h, 2, 16384); + RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000); + RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den); + RANGE_CHECK(cfg, g_profile, 0, 3); + RANGE_CHECK(cfg, rc_min_quantizer, 0, 63); + RANGE_CHECK(cfg, rc_max_quantizer, 0, 63); + RANGE_CHECK(cfg, g_threads, 0, 64); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK(cfg, g_lag_in_frames, 0, 25); +#else + RANGE_CHECK(cfg, g_lag_in_frames, 0, 0); +#endif + RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CBR); + RANGE_CHECK(cfg, rc_undershoot_pct, 0, 100); + RANGE_CHECK(cfg, rc_2pass_vbr_bias_pct, 0, 100); + RANGE_CHECK(cfg, kf_mode, VPX_KF_DISABLED, VPX_KF_AUTO); + //RANGE_CHECK_BOOL(cfg, g_delete_firstpassfile); + RANGE_CHECK_BOOL(cfg, rc_resize_allowed); + RANGE_CHECK(cfg, rc_dropframe_thresh, 0, 100); + RANGE_CHECK(cfg, rc_resize_up_thresh, 0, 100); + RANGE_CHECK(cfg, rc_resize_down_thresh, 0, 100); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_LAST_PASS); +#else + RANGE_CHECK(cfg, g_pass, VPX_RC_ONE_PASS, VPX_RC_ONE_PASS); +#endif + + /* VP8 does not support a lower bound on the keyframe interval in + * automatic keyframe placement mode. + */ + if (cfg->kf_mode != VPX_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist + && cfg->kf_min_dist > 0) + ERROR("kf_min_dist not supported in auto mode, use 0 " + "or kf_max_dist instead."); + + RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref); +#if !(CONFIG_REALTIME_ONLY) + RANGE_CHECK(vp8_cfg, encoding_mode, VP8_BEST_QUALITY_ENCODING, VP8_REAL_TIME_ENCODING); + RANGE_CHECK(vp8_cfg, cpu_used, -16, 16); + RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 6); +#else + RANGE_CHECK(vp8_cfg, encoding_mode, VP8_REAL_TIME_ENCODING, VP8_REAL_TIME_ENCODING); + + if (!((vp8_cfg->cpu_used >= -16 && vp8_cfg->cpu_used <= -4) || (vp8_cfg->cpu_used >= 4 && vp8_cfg->cpu_used <= 16))) + ERROR("cpu_used out of range [-16..-4] or [4..16]"); + + RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 0); +#endif + + RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION); + RANGE_CHECK(vp8_cfg, Sharpness, 0, 7); + RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 25); + RANGE_CHECK(vp8_cfg, arnr_strength, 0, 6); + RANGE_CHECK(vp8_cfg, arnr_type, 0, 0xffffffff); + + if (cfg->g_pass == VPX_RC_LAST_PASS) + { + int n_doubles = cfg->rc_twopass_stats_in.sz / sizeof(double); + int n_packets = cfg->rc_twopass_stats_in.sz / sizeof(FIRSTPASS_STATS); + double frames; + + if (!cfg->rc_twopass_stats_in.buf) + ERROR("rc_twopass_stats_in.buf not set."); + + if (cfg->rc_twopass_stats_in.sz % sizeof(FIRSTPASS_STATS)) + ERROR("rc_twopass_stats_in.sz indicates truncated packet."); + + if (cfg->rc_twopass_stats_in.sz < 2 * sizeof(FIRSTPASS_STATS)) + ERROR("rc_twopass_stats_in requires at least two packets."); + + frames = ((double *)cfg->rc_twopass_stats_in.buf)[n_doubles - 1]; + + if ((int)(frames + 0.5) != n_packets - 1) + ERROR("rc_twopass_stats_in missing EOS stats packet"); + } + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img) +{ + switch (img->fmt) + { + case IMG_FMT_YV12: + case IMG_FMT_I420: + case IMG_FMT_VPXI420: + case IMG_FMT_VPXYV12: + break; + default: + ERROR("Invalid image format. Only YV12 and I420 images are supported"); + } + + if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h)) + ERROR("Image size must match encoder init configuration size"); + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, + vpx_codec_enc_cfg_t cfg, + struct vp8_extracfg vp8_cfg) +{ + oxcf->multi_threaded = cfg.g_threads; + oxcf->Version = cfg.g_profile; + + oxcf->Width = cfg.g_w; + oxcf->Height = cfg.g_h; + /* guess a frame rate if out of whack, use 30 */ + oxcf->frame_rate = (double)(cfg.g_timebase.den) / (double)(cfg.g_timebase.num); + + if (oxcf->frame_rate > 180) + { + oxcf->frame_rate = 30; + } + + oxcf->error_resilient_mode = cfg.g_error_resilient; + + switch (cfg.g_pass) + { + case VPX_RC_ONE_PASS: + oxcf->Mode = MODE_BESTQUALITY; + break; + case VPX_RC_FIRST_PASS: + oxcf->Mode = MODE_FIRSTPASS; + break; + case VPX_RC_LAST_PASS: + oxcf->Mode = MODE_SECONDPASS_BEST; + break; + } + + if (cfg.g_pass == VPX_RC_FIRST_PASS) + { + oxcf->allow_lag = 0; + oxcf->lag_in_frames = 0; + } + else + { + oxcf->allow_lag = (cfg.g_lag_in_frames) > 0; + oxcf->lag_in_frames = cfg.g_lag_in_frames; + } + + oxcf->allow_df = (cfg.rc_dropframe_thresh > 0); + oxcf->drop_frames_water_mark = cfg.rc_dropframe_thresh; + + oxcf->allow_spatial_resampling = cfg.rc_resize_allowed; + oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh; + oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh; + + if (cfg.rc_end_usage == VPX_VBR) + { + oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; + } + else if (cfg.rc_end_usage == VPX_CBR) + { + oxcf->end_usage = USAGE_STREAM_FROM_SERVER; + } + + oxcf->target_bandwidth = cfg.rc_target_bitrate; + + oxcf->best_allowed_q = cfg.rc_min_quantizer; + oxcf->worst_allowed_q = cfg.rc_max_quantizer; + oxcf->fixed_q = -1; + + oxcf->under_shoot_pct = cfg.rc_undershoot_pct; + //oxcf->over_shoot_pct = cfg.rc_overshoot_pct; + + oxcf->maximum_buffer_size = cfg.rc_buf_sz / 1000; + oxcf->starting_buffer_level = cfg.rc_buf_initial_sz / 1000; + oxcf->optimal_buffer_level = cfg.rc_buf_optimal_sz / 1000; + + oxcf->two_pass_vbrbias = cfg.rc_2pass_vbr_bias_pct; + oxcf->two_pass_vbrmin_section = cfg.rc_2pass_vbr_minsection_pct; + oxcf->two_pass_vbrmax_section = cfg.rc_2pass_vbr_maxsection_pct; + + oxcf->auto_key = cfg.kf_mode == VPX_KF_AUTO + && cfg.kf_min_dist != cfg.kf_max_dist; + //oxcf->kf_min_dist = cfg.kf_min_dis; + oxcf->key_freq = cfg.kf_max_dist; + + //oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile; + //strcpy(oxcf->first_pass_file, cfg.g_firstpass_file); + + oxcf->cpu_used = vp8_cfg.cpu_used; + oxcf->encode_breakout = vp8_cfg.static_thresh; + oxcf->play_alternate = vp8_cfg.enable_auto_alt_ref; + oxcf->noise_sensitivity = vp8_cfg.noise_sensitivity; + oxcf->Sharpness = vp8_cfg.Sharpness; + oxcf->token_partitions = vp8_cfg.token_partitions; + + oxcf->two_pass_stats_in = cfg.rc_twopass_stats_in; + oxcf->output_pkt_list = vp8_cfg.pkt_list; + + oxcf->arnr_max_frames = vp8_cfg.arnr_max_frames; + oxcf->arnr_strength = vp8_cfg.arnr_strength; + oxcf->arnr_type = vp8_cfg.arnr_type; + + + /* + printf("Current VP8 Settings: \n"); + printf("target_bandwidth: %d\n", oxcf->target_bandwidth); + printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity); + printf("Sharpness: %d\n", oxcf->Sharpness); + printf("cpu_used: %d\n", oxcf->cpu_used); + printf("Mode: %d\n", oxcf->Mode); + printf("delete_first_pass_file: %d\n", oxcf->delete_first_pass_file); + printf("auto_key: %d\n", oxcf->auto_key); + printf("key_freq: %d\n", oxcf->key_freq); + printf("end_usage: %d\n", oxcf->end_usage); + printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct); + printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level); + printf("optimal_buffer_level: %d\n", oxcf->optimal_buffer_level); + printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size); + printf("fixed_q: %d\n", oxcf->fixed_q); + printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q); + printf("best_allowed_q: %d\n", oxcf->best_allowed_q); + printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling); + printf("resample_down_water_mark: %d\n", oxcf->resample_down_water_mark); + printf("resample_up_water_mark: %d\n", oxcf->resample_up_water_mark); + printf("allow_df: %d\n", oxcf->allow_df); + printf("drop_frames_water_mark: %d\n", oxcf->drop_frames_water_mark); + printf("two_pass_vbrbias: %d\n", oxcf->two_pass_vbrbias); + printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section); + printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section); + printf("allow_lag: %d\n", oxcf->allow_lag); + printf("lag_in_frames: %d\n", oxcf->lag_in_frames); + printf("play_alternate: %d\n", oxcf->play_alternate); + printf("Version: %d\n", oxcf->Version); + printf("multi_threaded: %d\n", oxcf->multi_threaded); + printf("encode_breakout: %d\n", oxcf->encode_breakout); + */ + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_set_config(vpx_codec_alg_priv_t *ctx, + const vpx_codec_enc_cfg_t *cfg) +{ + vpx_codec_err_t res; + + if ((cfg->g_w != ctx->cfg.g_w) || (cfg->g_h != ctx->cfg.g_h)) + ERROR("Cannot change width or height after initialization"); + + /* Prevent increasing lag_in_frames. This check is stricter than it needs + * to be -- the limit is not increasing past the first lag_in_frames + * value, but we don't track the initial config, only the last successful + * config. + */ + if ((cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames)) + ERROR("Cannot increase lag_in_frames"); + + res = validate_config(ctx, cfg, &ctx->vp8_cfg); + + if (!res) + { + ctx->cfg = *cfg; + set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg); + vp8_change_config(ctx->cpi, &ctx->oxcf); + } + + return res; +} + + +int vp8_reverse_trans(int); + + +static vpx_codec_err_t get_param(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + void *arg = va_arg(args, void *); + +#define MAP(id, var) case id: *(RECAST(id, arg)) = var; break + + if (!arg) + return VPX_CODEC_INVALID_PARAM; + + switch (ctrl_id) + { + MAP(VP8E_GET_LAST_QUANTIZER, vp8_get_quantizer(ctx->cpi)); + MAP(VP8E_GET_LAST_QUANTIZER_64, vp8_reverse_trans(vp8_get_quantizer(ctx->cpi))); + } + + return VPX_CODEC_OK; +#undef MAP +} + + +static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + struct vp8_extracfg xcfg = ctx->vp8_cfg; + +#define MAP(id, var) case id: var = CAST(id, args); break; + + switch (ctrl_id) + { + MAP(VP8E_SET_ENCODING_MODE, ctx->deprecated_mode); + MAP(VP8E_SET_CPUUSED, xcfg.cpu_used); + MAP(VP8E_SET_ENABLEAUTOALTREF, xcfg.enable_auto_alt_ref); + MAP(VP8E_SET_NOISE_SENSITIVITY, xcfg.noise_sensitivity); + MAP(VP8E_SET_SHARPNESS, xcfg.Sharpness); + MAP(VP8E_SET_STATIC_THRESHOLD, xcfg.static_thresh); + MAP(VP8E_SET_TOKEN_PARTITIONS, xcfg.token_partitions); + + MAP(VP8E_SET_ARNR_MAXFRAMES, xcfg.arnr_max_frames); + MAP(VP8E_SET_ARNR_STRENGTH , xcfg.arnr_strength); + MAP(VP8E_SET_ARNR_TYPE , xcfg.arnr_type); + + } + + res = validate_config(ctx, &ctx->cfg, &xcfg); + + if (!res) + { + ctx->vp8_cfg = xcfg; + set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg); + vp8_change_config(ctx->cpi, &ctx->oxcf); + } + + return res; +#undef MAP +} +static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx) +{ + vpx_codec_err_t res = VPX_DEC_OK; + struct vpx_codec_alg_priv *priv; + vpx_codec_enc_cfg_t *cfg; + unsigned int i; + + VP8_PTR optr; + + if (!ctx->priv) + { + priv = calloc(1, sizeof(struct vpx_codec_alg_priv)); + + if (priv) + { + ctx->priv = &priv->base; + ctx->priv->sz = sizeof(*ctx->priv); + ctx->priv->iface = ctx->iface; + ctx->priv->alg_priv = priv; + ctx->priv->init_flags = ctx->init_flags; + + if (ctx->config.enc) + { + /* Update the reference to the config structure to an + * internal copy. + */ + ctx->priv->alg_priv->cfg = *ctx->config.enc; + ctx->config.enc = &ctx->priv->alg_priv->cfg; + } + + cfg = &ctx->priv->alg_priv->cfg; + + /* Select the extra vp6 configuration table based on the current + * usage value. If the current usage value isn't found, use the + * values for usage case 0. + */ + for (i = 0; + extracfg_map[i].usage && extracfg_map[i].usage != cfg->g_usage; + i++); + + priv->vp8_cfg = extracfg_map[i].cfg; + priv->vp8_cfg.pkt_list = &priv->pkt_list.head; + + priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 2; + + if (priv->cx_data_sz < 4096) priv->cx_data_sz = 4096; + + priv->cx_data = malloc(priv->cx_data_sz); + priv->deprecated_mode = NO_MODE_SET; + + vp8_initialize(); + + res = validate_config(priv, &priv->cfg, &priv->vp8_cfg); + + if (!res) + { + set_vp8e_config(&ctx->priv->alg_priv->oxcf, ctx->priv->alg_priv->cfg, ctx->priv->alg_priv->vp8_cfg); + optr = vp8_create_compressor(&ctx->priv->alg_priv->oxcf); + + if (!optr) + res = VPX_CODEC_MEM_ERROR; + else + ctx->priv->alg_priv->cpi = optr; + } + } + } + + return res; +} + +static vpx_codec_err_t vp8e_destroy(vpx_codec_alg_priv_t *ctx) +{ + + free(ctx->cx_data); + vp8_remove_compressor(&ctx->cpi); + free(ctx); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, + YV12_BUFFER_CONFIG *yv12) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + yv12->y_buffer = img->planes[PLANE_Y]; + yv12->u_buffer = img->planes[PLANE_U]; + yv12->v_buffer = img->planes[PLANE_V]; + + yv12->y_width = img->d_w; + yv12->y_height = img->d_h; + yv12->uv_width = (1 + yv12->y_width) / 2; + yv12->uv_height = (1 + yv12->y_height) / 2; + + yv12->y_stride = img->stride[PLANE_Y]; + yv12->uv_stride = img->stride[PLANE_U]; + + yv12->border = (img->stride[PLANE_Y] - img->w) / 2; + yv12->clrtype = (img->fmt == IMG_FMT_VPXI420 || img->fmt == IMG_FMT_VPXYV12); //REG_YUV = 0 + return res; +} + +static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx, + unsigned long duration, + unsigned long deadline) +{ + unsigned int new_qc; + +#if !(CONFIG_REALTIME_ONLY) + /* Use best quality mode if no deadline is given. */ + new_qc = MODE_BESTQUALITY; + + if (deadline) + { + uint64_t duration_us; + + /* Convert duration parameter from stream timebase to microseconds */ + duration_us = (uint64_t)duration * 1000000 + * (uint64_t)ctx->cfg.g_timebase.num + / (uint64_t)ctx->cfg.g_timebase.den; + + /* If the deadline is more that the duration this frame is to be shown, + * use good quality mode. Otherwise use realtime mode. + */ + new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME; + } + +#else + new_qc = MODE_REALTIME; +#endif + + switch (ctx->deprecated_mode) + { + case VP8_BEST_QUALITY_ENCODING: + new_qc = MODE_BESTQUALITY; + break; + case VP8_GOOD_QUALITY_ENCODING: + new_qc = MODE_GOODQUALITY; + break; + case VP8_REAL_TIME_ENCODING: + new_qc = MODE_REALTIME; + break; + } + + if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS) + new_qc = MODE_FIRSTPASS; + else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS) + new_qc = (new_qc == MODE_BESTQUALITY) + ? MODE_SECONDPASS_BEST + : MODE_SECONDPASS; + + if (ctx->oxcf.Mode != new_qc) + { + ctx->oxcf.Mode = new_qc; + vp8_change_config(ctx->cpi, &ctx->oxcf); + } +} + + +static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + if (img) + res = validate_img(ctx, img); + + pick_quickcompress_mode(ctx, duration, deadline); + vpx_codec_pkt_list_init(&ctx->pkt_list); + + /* Handle Flags */ + if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF)) + || ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF))) + { + ctx->base.err_detail = "Conflicting flags."; + return VPX_CODEC_INVALID_PARAM; + } + + if (flags & (VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF + | VP8_EFLAG_NO_REF_ARF)) + { + int ref = 7; + + if (flags & VP8_EFLAG_NO_REF_LAST) + ref ^= VP8_LAST_FLAG; + + if (flags & VP8_EFLAG_NO_REF_GF) + ref ^= VP8_GOLD_FLAG; + + if (flags & VP8_EFLAG_NO_REF_ARF) + ref ^= VP8_ALT_FLAG; + + vp8_use_as_reference(ctx->cpi, ref); + } + + if (flags & (VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF + | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_FORCE_GF + | VP8_EFLAG_FORCE_ARF)) + { + int upd = 7; + + if (flags & VP8_EFLAG_NO_UPD_LAST) + upd ^= VP8_LAST_FLAG; + + if (flags & VP8_EFLAG_NO_UPD_GF) + upd ^= VP8_GOLD_FLAG; + + if (flags & VP8_EFLAG_NO_UPD_ARF) + upd ^= VP8_ALT_FLAG; + + vp8_update_reference(ctx->cpi, upd); + } + + if (flags & VP8_EFLAG_NO_UPD_ENTROPY) + { + vp8_update_entropy(ctx->cpi, 0); + } + + /* Handle fixed keyframe intervals */ + if (ctx->cfg.kf_mode == VPX_KF_AUTO + && ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) + { + if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) + { + flags |= VPX_EFLAG_FORCE_KF; + ctx->fixed_kf_cntr = 0; + } + } + + /* Initialize the encoder instance on the first frame*/ + if (!res && ctx->cpi) + { + unsigned int lib_flags; + YV12_BUFFER_CONFIG sd; + INT64 dst_time_stamp, dst_end_time_stamp; + unsigned long size, cx_data_sz; + unsigned char *cx_data; + + /* Set up internal flags */ + if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) + ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1; + + /* Convert API flags to internal codec lib flags */ + lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; + + /* vp8 use 10,000,000 ticks/second as time stamp */ + dst_time_stamp = pts * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den; + dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den; + + if (img != NULL) + { + res = image2yuvconfig(img, &sd); + + if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, + &sd, dst_time_stamp, dst_end_time_stamp)) + { + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + res = update_error_state(ctx, &cpi->common.error); + } + + /* reset for next frame */ + ctx->next_frame_flag = 0; + } + + cx_data = ctx->cx_data; + cx_data_sz = ctx->cx_data_sz; + lib_flags = 0; + + while (cx_data_sz >= ctx->cx_data_sz / 2 + && -1 != vp8_get_compressed_data(ctx->cpi, &lib_flags, &size, cx_data, &dst_time_stamp, &dst_end_time_stamp, !img)) + { + if (size) + { + vpx_codec_pts_t round, delta; + vpx_codec_cx_pkt_t pkt; + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + + /* Add the frame packet to the list of returned packets. */ + round = 1000000 * ctx->cfg.g_timebase.num / 2 - 1; + delta = (dst_end_time_stamp - dst_time_stamp); + pkt.kind = VPX_CODEC_CX_FRAME_PKT; + pkt.data.frame.buf = cx_data; + pkt.data.frame.sz = size; + pkt.data.frame.pts = + (dst_time_stamp * ctx->cfg.g_timebase.den + round) + / ctx->cfg.g_timebase.num / 10000000; + pkt.data.frame.duration = + (delta * ctx->cfg.g_timebase.den + round) + / ctx->cfg.g_timebase.num / 10000000; + pkt.data.frame.flags = lib_flags << 16; + + if (lib_flags & FRAMEFLAGS_KEY) + pkt.data.frame.flags |= VPX_FRAME_IS_KEY; + + if (!cpi->common.show_frame) + { + pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE; + + // TODO: ideally this timestamp should be as close as + // possible to the prior PTS so that if a decoder uses + // pts to schedule when to do this, we start right after + // last frame was decoded. Maybe should be set to + // last time stamp. Invisible frames have no duration.. + pkt.data.frame.pts --; + pkt.data.frame.duration = 0; + } + + vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); + + //printf("timestamp: %lld, duration: %d\n", pkt->data.frame.pts, pkt->data.frame.duration); + cx_data += size; + cx_data_sz -= size; + } + } + } + + return res; +} + + +static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter) +{ + return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter); +} + +static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + vp8_set_reference(ctx->cpi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + vp8_get_reference(ctx->cpi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +static vpx_codec_err_t vp8e_set_previewpp(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); + + if (data) + { + ctx->preview_ppcfg = *((vp8_postproc_cfg_t *)data); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; +} + + +static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx) +{ + + YV12_BUFFER_CONFIG sd; + + if (0 == vp8_get_preview_raw_frame(ctx->cpi, &sd, ctx->preview_ppcfg.deblocking_level, ctx->preview_ppcfg.noise_level, ctx->preview_ppcfg.post_proc_flag)) + { + + /* + vpx_img_wrap(&ctx->preview_img, IMG_FMT_YV12, + sd.y_width + 2*VP8BORDERINPIXELS, + sd.y_height + 2*VP8BORDERINPIXELS, + 1, + sd.buffer_alloc); + vpx_img_set_rect(&ctx->preview_img, + VP8BORDERINPIXELS, VP8BORDERINPIXELS, + sd.y_width, sd.y_height); + */ + + ctx->preview_img.bps = 12; + ctx->preview_img.planes[PLANE_Y] = sd.y_buffer; + ctx->preview_img.planes[PLANE_U] = sd.u_buffer; + ctx->preview_img.planes[PLANE_V] = sd.v_buffer; + + if (sd.clrtype == REG_YUV) + ctx->preview_img.fmt = IMG_FMT_I420; + else + ctx->preview_img.fmt = IMG_FMT_VPXI420; + + ctx->preview_img.x_chroma_shift = 1; + ctx->preview_img.y_chroma_shift = 1; + + ctx->preview_img.d_w = ctx->cfg.g_w; + ctx->preview_img.d_h = ctx->cfg.g_h; + ctx->preview_img.stride[PLANE_Y] = sd.y_stride; + ctx->preview_img.stride[PLANE_U] = sd.uv_stride; + ctx->preview_img.stride[PLANE_V] = sd.uv_stride; + ctx->preview_img.w = sd.y_width; + ctx->preview_img.h = sd.y_height; + + return &ctx->preview_img; + } + else + return NULL; +} + +static vpx_codec_err_t vp8e_update_entropy(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int update = va_arg(args, int); + vp8_update_entropy(ctx->cpi, update); + return VPX_CODEC_OK; + +} + +static vpx_codec_err_t vp8e_update_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int update = va_arg(args, int); + vp8_update_reference(ctx->cpi, update); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_use_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + int reference_flag = va_arg(args, int); + vp8_use_as_reference(ctx->cpi, reference_flag); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8e_set_roi_map(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_roi_map_t *data = va_arg(args, vpx_roi_map_t *); + + if (data) + { + vpx_roi_map_t *roi = (vpx_roi_map_t *)data; + + if (!vp8_set_roimap(ctx->cpi, roi->roi_map, roi->rows, roi->cols, roi->delta_q, roi->delta_lf, roi->static_threshold)) + return VPX_CODEC_OK; + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + + +static vpx_codec_err_t vp8e_set_activemap(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vpx_active_map_t *data = va_arg(args, vpx_active_map_t *); + + if (data) + { + + vpx_active_map_t *map = (vpx_active_map_t *)data; + + if (!vp8_set_active_map(ctx->cpi, map->active_map, map->rows, map->cols)) + return VPX_CODEC_OK; + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + +static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_scaling_mode_t *data = va_arg(args, vpx_scaling_mode_t *); + + if (data) + { + int res; + vpx_scaling_mode_t scalemode = *(vpx_scaling_mode_t *)data ; + res = vp8_set_internal_size(ctx->cpi, scalemode.h_scaling_mode, scalemode.v_scaling_mode); + + if (!res) + { + /*force next frame a key frame to effect scaling mode */ + ctx->next_frame_flag |= FRAMEFLAGS_KEY; + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + } + else + return VPX_CODEC_INVALID_PARAM; +} + + +static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = +{ + {VP8_SET_REFERENCE, vp8e_set_reference}, + {VP8_COPY_REFERENCE, vp8e_get_reference}, + {VP8_SET_POSTPROC, vp8e_set_previewpp}, + {VP8E_UPD_ENTROPY, vp8e_update_entropy}, + {VP8E_UPD_REFERENCE, vp8e_update_reference}, + {VP8E_USE_REFERENCE, vp8e_use_reference}, + {VP8E_SET_ROI_MAP, vp8e_set_roi_map}, + {VP8E_SET_ACTIVEMAP, vp8e_set_activemap}, + {VP8E_SET_SCALEMODE, vp8e_set_scalemode}, + {VP8E_SET_ENCODING_MODE, set_param}, + {VP8E_SET_CPUUSED, set_param}, + {VP8E_SET_NOISE_SENSITIVITY, set_param}, + {VP8E_SET_ENABLEAUTOALTREF, set_param}, + {VP8E_SET_SHARPNESS, set_param}, + {VP8E_SET_STATIC_THRESHOLD, set_param}, + {VP8E_SET_TOKEN_PARTITIONS, set_param}, + {VP8E_GET_LAST_QUANTIZER, get_param}, + {VP8E_GET_LAST_QUANTIZER_64, get_param}, + {VP8E_SET_ARNR_MAXFRAMES, set_param}, + {VP8E_SET_ARNR_STRENGTH , set_param}, + {VP8E_SET_ARNR_TYPE , set_param}, + { -1, NULL}, +}; + +static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = +{ + { + 0, + { + 0, /* g_usage */ + 0, /* g_threads */ + 0, /* g_profile */ + + 320, /* g_width */ + 240, /* g_height */ + {1, 30}, /* g_timebase */ + + 0, /* g_error_resilient */ + + VPX_RC_ONE_PASS, /* g_pass */ + + 0, /* g_lag_in_frames */ + + 70, /* rc_dropframe_thresh */ + 0, /* rc_resize_allowed */ + 60, /* rc_resize_down_thresold */ + 30, /* rc_resize_up_thresold */ + + VPX_VBR, /* rc_end_usage */ +#if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION) + {0}, /* rc_twopass_stats_in */ +#endif + 256, /* rc_target_bandwidth */ + + 4, /* rc_min_quantizer */ + 63, /* rc_max_quantizer */ + + 95, /* rc_undershoot_pct */ + 200, /* rc_overshoot_pct */ + + 6000, /* rc_max_buffer_size */ + 4000, /* rc_buffer_initial_size; */ + 5000, /* rc_buffer_optimal_size; */ + + 50, /* rc_two_pass_vbrbias */ + 0, /* rc_two_pass_vbrmin_section */ + 400, /* rc_two_pass_vbrmax_section */ + + /* keyframing settings (kf) */ + VPX_KF_AUTO, /* g_kfmode*/ + 0, /* kf_min_dist */ + 9999, /* kf_max_dist */ + +#if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION) + 1, /* g_delete_first_pass_file */ + "vp8.fpf" /* first pass filename */ +#endif + }}, + { -1, {NOT_IMPLEMENTED}} +}; + + +#ifndef VERSION_STRING +#define VERSION_STRING +#endif +vpx_codec_iface_t vpx_codec_vp8_cx_algo = +{ + "vpx Technologies VP8 Encoder" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR, + /* vpx_codec_caps_t caps; */ + vp8e_init, /* vpx_codec_init_fn_t init; */ + vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */ + vp8e_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */ + NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */ + { + NOT_IMPLEMENTED, /* vpx_codec_peek_si_fn_t peek_si; */ + NOT_IMPLEMENTED, /* vpx_codec_get_si_fn_t get_si; */ + NOT_IMPLEMENTED, /* vpx_codec_decode_fn_t decode; */ + NOT_IMPLEMENTED, /* vpx_codec_frame_get_fn_t frame_get; */ + }, + { + vp8e_usage_cfg_map, /* vpx_codec_enc_cfg_map_t peek_si; */ + vp8e_encode, /* vpx_codec_encode_fn_t encode; */ + vp8e_get_cxdata, /* vpx_codec_get_cx_data_fn_t frame_get; */ + vp8e_set_config, + NOT_IMPLEMENTED, + vp8e_get_preview, + } /* encoder functions */ +}; + + +/* + * BEGIN BACKWARDS COMPATIBILITY SHIM. + */ +#define FORCE_KEY 2 +static vpx_codec_err_t api1_control(vpx_codec_alg_priv_t *ctx, + int ctrl_id, + va_list args) +{ + vpx_codec_ctrl_fn_map_t *entry; + + switch (ctrl_id) + { + case VP8E_SET_FLUSHFLAG: + /* VP8 sample code did VP8E_SET_FLUSHFLAG followed by + * vpx_codec_get_cx_data() rather than vpx_codec_encode(). + */ + return vp8e_encode(ctx, NULL, 0, 0, 0, 0); + case VP8E_SET_FRAMETYPE: + ctx->base.enc.tbd |= FORCE_KEY; + return VPX_CODEC_OK; + } + + for (entry = vp8e_ctf_maps; entry && entry->fn; entry++) + { + if (!entry->ctrl_id || entry->ctrl_id == ctrl_id) + { + return entry->fn(ctx, ctrl_id, args); + } + } + + return VPX_CODEC_ERROR; +} + + +static vpx_codec_ctrl_fn_map_t api1_ctrl_maps[] = +{ + {0, api1_control}, + { -1, NULL} +}; + + +static vpx_codec_err_t api1_encode(vpx_codec_alg_priv_t *ctx, + const vpx_image_t *img, + vpx_codec_pts_t pts, + unsigned long duration, + vpx_enc_frame_flags_t flags, + unsigned long deadline) +{ + int force = ctx->base.enc.tbd; + + ctx->base.enc.tbd = 0; + return vp8e_encode + (ctx, + img, + pts, + duration, + flags | ((force & FORCE_KEY) ? VPX_EFLAG_FORCE_KF : 0), + deadline); +} + + +vpx_codec_iface_t vpx_enc_vp8_algo = +{ + "vpx Technologies VP8 Encoder (Deprecated API)" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_ENCODER, + /* vpx_codec_caps_t caps; */ + vp8e_init, /* vpx_codec_init_fn_t init; */ + vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */ + api1_ctrl_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + NOT_IMPLEMENTED, /* vpx_codec_get_mmap_fn_t get_mmap; */ + NOT_IMPLEMENTED, /* vpx_codec_set_mmap_fn_t set_mmap; */ + {NOT_IMPLEMENTED}, /* decoder functions */ + { + vp8e_usage_cfg_map, /* vpx_codec_enc_cfg_map_t peek_si; */ + api1_encode, /* vpx_codec_encode_fn_t encode; */ + vp8e_get_cxdata, /* vpx_codec_get_cx_data_fn_t frame_get; */ + vp8e_set_config, + NOT_IMPLEMENTED, + vp8e_get_preview, + } /* encoder functions */ +};
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c new file mode 100644 index 0000000..3e6cdf4 --- /dev/null +++ b/vp8/vp8_dx_iface.c
@@ -0,0 +1,698 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include <stdlib.h> +#include <string.h> +#include "vpx_codec/vpx_decoder.h" +#include "vp8dx.h" +#include "vpx_codec/internal/vpx_codec_internal.h" +#include "vpx_version.h" +#include "onyxd.h" +#include "onyxd_int.h" + +#define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0) + +#if CONFIG_BIG_ENDIAN +# define swap4(d)\ + ((d&0x000000ff)<<24) | \ + ((d&0x0000ff00)<<8) | \ + ((d&0x00ff0000)>>8) | \ + ((d&0xff000000)>>24) +# define swap2(d)\ + ((d&0x000000ff)<<8) | \ + ((d&0x0000ff00)>>8) +#else +# define swap4(d) d +# define swap2(d) d +#endif +typedef vpx_codec_stream_info_t vp8_stream_info_t; + +/* Structures for handling memory allocations */ +typedef enum +{ + VP8_SEG_ALG_PRIV = 256, + VP8_SEG_MAX +} mem_seg_id_t; +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) + +static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t); + +typedef struct +{ + unsigned int id; + unsigned long sz; + unsigned int align; + unsigned int flags; + unsigned long(*calc_sz)(const vpx_codec_dec_cfg_t *, vpx_codec_flags_t); +} mem_req_t; + +static const mem_req_t vp8_mem_req_segs[] = +{ + {VP8_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, vp8_priv_sz}, + {VP8_SEG_MAX, 0, 0, 0, NULL} +}; + +struct vpx_codec_alg_priv +{ + vpx_codec_priv_t base; + vpx_codec_mmap_t mmaps[NELEMENTS(vp8_mem_req_segs)-1]; + vpx_codec_dec_cfg_t cfg; + vp8_stream_info_t si; + int defer_alloc; + int decoder_init; + VP8D_PTR pbi; + int postproc_cfg_set; + vp8_postproc_cfg_t postproc_cfg; + vpx_image_t img; + int img_setup; + int img_avail; +}; + +static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t flags) +{ + /* Although this declaration is constant, we can't use it in the requested + * segments list because we want to define the requested segments list + * before defining the private type (so that the number of memory maps is + * known) + */ + (void)si; + return sizeof(vpx_codec_alg_priv_t); +} + + +static void vp8_mmap_dtor(vpx_codec_mmap_t *mmap) +{ + free(mmap->priv); +} + +static vpx_codec_err_t vp8_mmap_alloc(vpx_codec_mmap_t *mmap) +{ + vpx_codec_err_t res; + unsigned int align; + + align = mmap->align ? mmap->align - 1 : 0; + + if (mmap->flags & VPX_CODEC_MEM_ZERO) + mmap->priv = calloc(1, mmap->sz + align); + else + mmap->priv = malloc(mmap->sz + align); + + res = (mmap->priv) ? VPX_CODEC_OK : VPX_CODEC_MEM_ERROR; + mmap->base = (void *)((((uintptr_t)mmap->priv) + align) & ~(uintptr_t)align); + mmap->dtor = vp8_mmap_dtor; + return res; +} + +static vpx_codec_err_t vp8_validate_mmaps(const vp8_stream_info_t *si, + const vpx_codec_mmap_t *mmaps, + vpx_codec_flags_t init_flags) +{ + int i; + vpx_codec_err_t res = VPX_CODEC_OK; + + for (i = 0; i < NELEMENTS(vp8_mem_req_segs) - 1; i++) + { + /* Ensure the segment has been allocated */ + if (!mmaps[i].base) + { + res = VPX_CODEC_MEM_ERROR; + break; + } + + /* Verify variable size segment is big enough for the current si. */ + if (vp8_mem_req_segs[i].calc_sz) + { + vpx_codec_dec_cfg_t cfg; + + cfg.w = si->w; + cfg.h = si->h; + + if (mmaps[i].sz < vp8_mem_req_segs[i].calc_sz(&cfg, init_flags)) + { + res = VPX_CODEC_MEM_ERROR; + break; + } + } + } + + return res; +} + +static void vp8_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) +{ + int i; + + ctx->priv = mmap->base; + ctx->priv->sz = sizeof(*ctx->priv); + ctx->priv->iface = ctx->iface; + ctx->priv->alg_priv = mmap->base; + + for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) + ctx->priv->alg_priv->mmaps[i].id = vp8_mem_req_segs[i].id; + + ctx->priv->alg_priv->mmaps[0] = *mmap; + ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si); + ctx->priv->init_flags = ctx->init_flags; + + if (ctx->config.dec) + { + /* Update the reference to the config structure to an internal copy. */ + ctx->priv->alg_priv->cfg = *ctx->config.dec; + ctx->config.dec = &ctx->priv->alg_priv->cfg; + } +} + +static void *mmap_lkup(vpx_codec_alg_priv_t *ctx, int id) +{ + int i; + + for (i = 0; i < NELEMENTS(vp8_mem_req_segs); i++) + if (ctx->mmaps[i].id == id) + return ctx->mmaps[i].base; + + return NULL; +} +static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx) +{ + /* + ctx->pbi = mmap_lkup(ctx, VP6_SEG_PB_INSTANCE); + ctx->pbi->mbi.block_dx_info[0].idct_output_ptr = mmap_lkup(ctx, VP6_SEG_IDCT_BUFFER); + ctx->pbi->loop_filtered_block = mmap_lkup(ctx, VP6_SEG_LF_BLOCK); + ctx->pbi->huff = mmap_lkup(ctx, VP6_SEG_HUFF); + ctx->pbi->mbi.coeffs_base_ptr = mmap_lkup(ctx, VP6_SEG_COEFFS); + ctx->pbi->fc.above_y = mmap_lkup(ctx, VP6_SEG_ABOVEY); + ctx->pbi->fc.above_u = mmap_lkup(ctx, VP6_SEG_ABOVEU); + ctx->pbi->fc.above_v = mmap_lkup(ctx, VP6_SEG_ABOVEV); + ctx->pbi->prediction_mode = mmap_lkup(ctx, VP6_SEG_PRED_MODES); + ctx->pbi->mbmotion_vector = mmap_lkup(ctx, VP6_SEG_MV_FIELD); + ctx->pbi->fb_storage_ptr[0] = mmap_lkup(ctx, VP6_SEG_IMG0_STRG); + ctx->pbi->fb_storage_ptr[1] = mmap_lkup(ctx, VP6_SEG_IMG1_STRG); + ctx->pbi->fb_storage_ptr[2] = mmap_lkup(ctx, VP6_SEG_IMG2_STRG); + #if CONFIG_NEW_TOKENS + ctx->pbi->token_graph = mmap_lkup(ctx, VP6_SEG_TOKEN_GRAPH); + #endif + #if CONFIG_POSTPROC + ctx->pbi->postproc.deblock.fragment_variances = mmap_lkup(ctx, VP6_SEG_DEBLOCKER); + ctx->pbi->fb_storage_ptr[3] = mmap_lkup(ctx, VP6_SEG_PP_IMG_STRG); + #endif + */ +} + +static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + /* This function only allocates space for the vpx_codec_alg_priv_t + * structure. More memory may be required at the time the stream + * information becomes known. + */ + if (!ctx->priv) + { + vpx_codec_mmap_t mmap; + + mmap.id = vp8_mem_req_segs[0].id; + mmap.sz = sizeof(vpx_codec_alg_priv_t); + mmap.align = vp8_mem_req_segs[0].align; + mmap.flags = vp8_mem_req_segs[0].flags; + + res = vp8_mmap_alloc(&mmap); + + if (!res) + vp8_init_ctx(ctx, &mmap); + + ctx->priv->alg_priv->defer_alloc = 1; + /*post processing level initialized to do nothing */ + + } + + return res; +} + +static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx) +{ + int i; + + vp8dx_remove_decompressor(ctx->pbi); + + for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) + { + if (ctx->mmaps[i].dtor) + ctx->mmaps[i].dtor(&ctx->mmaps[i]); + } + + return VPX_CODEC_OK; +} + +static vpx_codec_err_t vp8_peek_si(const uint8_t *data, + unsigned int data_sz, + vpx_codec_stream_info_t *si) +{ + + vpx_codec_err_t res = VPX_CODEC_OK; + { + /*Parse from VP8 compressed data, the implies knowledge of the + *VP8 bitsteam. + * First 3 byte header including version, frame type and an offset + * Next 3 bytes are image sizewith 12 bit each for width and height + */ + + si->is_kf = 0; + + if (data_sz >= 10 && !(data[0] & 0x01)) /* I-Frame */ + { + const uint8_t *c = data + 3; + si->is_kf = 1; + + // vet via sync code + if (c[0] != 0x9d || c[1] != 0x01 || c[2] != 0x2a) + res = VPX_CODEC_UNSUP_BITSTREAM; + + si->w = swap2(*(const unsigned short *)(c + 3)) & 0x3fff; + si->h = swap2(*(const unsigned short *)(c + 5)) & 0x3fff; + + //printf("w=%d, h=%d\n", si->w, si->h); + if (!(si->h | si->w)) + res = VPX_CODEC_UNSUP_BITSTREAM; + } + else + res = VPX_CODEC_UNSUP_BITSTREAM; + } + + return res; + +} + +static vpx_codec_err_t vp8_get_si(vpx_codec_alg_priv_t *ctx, + vpx_codec_stream_info_t *si) +{ + + unsigned int sz; + + if (si->sz >= sizeof(vp8_stream_info_t)) + sz = sizeof(vp8_stream_info_t); + else + sz = sizeof(vpx_codec_stream_info_t); + + memcpy(si, &ctx->si, sz); + si->sz = sz; + + return VPX_CODEC_OK; +} + + +static vpx_codec_err_t +update_error_state(vpx_codec_alg_priv_t *ctx, + const struct vpx_internal_error_info *error) +{ + vpx_codec_err_t res; + + if ((res = error->error_code)) + ctx->base.err_detail = error->has_detail + ? error->detail + : NULL; + + return res; +} + + +static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, + const uint8_t *data, + unsigned int data_sz, + void *user_priv, + long deadline) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + + ctx->img_avail = 0; + + /* Determine the stream parameters */ + if (!ctx->si.h) + res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si); + + + /* Perform deferred allocations, if required */ + if (!res && ctx->defer_alloc) + { + int i; + + for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) + { + vpx_codec_dec_cfg_t cfg; + + cfg.w = ctx->si.w; + cfg.h = ctx->si.h; + ctx->mmaps[i].id = vp8_mem_req_segs[i].id; + ctx->mmaps[i].sz = vp8_mem_req_segs[i].sz; + ctx->mmaps[i].align = vp8_mem_req_segs[i].align; + ctx->mmaps[i].flags = vp8_mem_req_segs[i].flags; + + if (!ctx->mmaps[i].sz) + ctx->mmaps[i].sz = vp8_mem_req_segs[i].calc_sz(&cfg, + ctx->base.init_flags); + + res = vp8_mmap_alloc(&ctx->mmaps[i]); + } + + if (!res) + vp8_finalize_mmaps(ctx); + + ctx->defer_alloc = 0; + } + + /* Initialize the decoder instance on the first frame*/ + if (!res && !ctx->decoder_init) + { + res = vp8_validate_mmaps(&ctx->si, ctx->mmaps, ctx->base.init_flags); + + if (!res) + { + VP8D_CONFIG oxcf; + VP8D_PTR optr; + + vp8dx_initialize(); + + oxcf.Width = ctx->si.w; + oxcf.Height = ctx->si.h; + oxcf.Version = 9; + oxcf.postprocess = 0; + oxcf.max_threads = ctx->cfg.threads; + + optr = vp8dx_create_decompressor(&oxcf); + + /* If postprocessing was enabled by the application and a + * configuration has not been provided, default it. + */ + if (!ctx->postproc_cfg_set + && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) + { + ctx->postproc_cfg.post_proc_flag = + VP8_DEBLOCK | VP8_DEMACROBLOCK; + ctx->postproc_cfg.deblocking_level = 4; + ctx->postproc_cfg.noise_level = 0; + } + + if (!optr) + res = VPX_CODEC_ERROR; + else + ctx->pbi = optr; + } + + ctx->decoder_init = 1; + } + + if (!res && ctx->pbi) + { + YV12_BUFFER_CONFIG sd; + INT64 time_stamp = 0, time_end_stamp = 0; + int ppflag = 0; + int ppdeblocking = 0; + int ppnoise = 0; + + if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) + { + ppflag = ctx->postproc_cfg.post_proc_flag; + ppdeblocking = ctx->postproc_cfg.deblocking_level; + ppnoise = ctx->postproc_cfg.noise_level; + } + + if (vp8dx_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) + { + VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; + res = update_error_state(ctx, &pbi->common.error); + } + + if (!res && 0 == vp8dx_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, ppdeblocking, ppnoise, ppflag)) + { + /* Align width/height */ + unsigned int a_w = (sd.y_width + 15) & ~15; + unsigned int a_h = (sd.y_height + 15) & ~15; + + vpx_img_wrap(&ctx->img, IMG_FMT_I420, + a_w + 2 * VP8BORDERINPIXELS, + a_h + 2 * VP8BORDERINPIXELS, + 1, + sd.buffer_alloc); + vpx_img_set_rect(&ctx->img, + VP8BORDERINPIXELS, VP8BORDERINPIXELS, + sd.y_width, sd.y_height); + ctx->img_avail = 1; + + } + } + + return res; +} + +static vpx_image_t *vp8_get_frame(vpx_codec_alg_priv_t *ctx, + vpx_codec_iter_t *iter) +{ + vpx_image_t *img = NULL; + + if (ctx->img_avail) + { + /* iter acts as a flip flop, so an image is only returned on the first + * call to get_frame. + */ + if (!(*iter)) + { + img = &ctx->img; + *iter = img; + } + } + + return img; +} + + +static +vpx_codec_err_t vp8_xma_get_mmap(const vpx_codec_ctx_t *ctx, + vpx_codec_mmap_t *mmap, + vpx_codec_iter_t *iter) +{ + vpx_codec_err_t res; + const mem_req_t *seg_iter = *iter; + + /* Get address of next segment request */ + do + { + if (!seg_iter) + seg_iter = vp8_mem_req_segs; + else if (seg_iter->id != VP8_SEG_MAX) + seg_iter++; + + *iter = (vpx_codec_iter_t)seg_iter; + + if (seg_iter->id != VP8_SEG_MAX) + { + mmap->id = seg_iter->id; + mmap->sz = seg_iter->sz; + mmap->align = seg_iter->align; + mmap->flags = seg_iter->flags; + + if (!seg_iter->sz) + mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags); + + res = VPX_CODEC_OK; + } + else + res = VPX_CODEC_LIST_END; + } + while (!mmap->sz && res != VPX_CODEC_LIST_END); + + return res; +} + +static vpx_codec_err_t vp8_xma_set_mmap(vpx_codec_ctx_t *ctx, + const vpx_codec_mmap_t *mmap) +{ + vpx_codec_err_t res = VPX_CODEC_MEM_ERROR; + int i, done; + + if (!ctx->priv) + { + if (mmap->id == VP8_SEG_ALG_PRIV) + { + if (!ctx->priv) + { + vp8_init_ctx(ctx, mmap); + res = VPX_CODEC_OK; + } + } + } + + done = 1; + + if (ctx->priv->alg_priv) + { + for (i = 0; i < NELEMENTS(vp8_mem_req_segs); i++) + { + if (ctx->priv->alg_priv->mmaps[i].id == mmap->id) + if (!ctx->priv->alg_priv->mmaps[i].base) + { + ctx->priv->alg_priv->mmaps[i] = *mmap; + res = VPX_CODEC_OK; + } + + done &= (ctx->priv->alg_priv->mmaps[i].base != NULL); + } + } + + if (done && !res) + { + vp8_finalize_mmaps(ctx->priv->alg_priv); + res = ctx->iface->init(ctx); + } + + return res; +} + +static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, + YV12_BUFFER_CONFIG *yv12) +{ + vpx_codec_err_t res = VPX_CODEC_OK; + yv12->y_buffer = img->planes[PLANE_Y]; + yv12->u_buffer = img->planes[PLANE_U]; + yv12->v_buffer = img->planes[PLANE_V]; + + yv12->y_width = img->d_w; + yv12->y_height = img->d_h; + yv12->uv_width = yv12->y_width / 2; + yv12->uv_height = yv12->y_height / 2; + + yv12->y_stride = img->stride[PLANE_Y]; + yv12->uv_stride = img->stride[PLANE_U]; + + yv12->border = (img->stride[PLANE_Y] - img->d_w) / 2; + yv12->clrtype = (img->fmt == IMG_FMT_VPXI420 || img->fmt == IMG_FMT_VPXYV12); + + return res; +} + + +static vpx_codec_err_t vp8_set_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + + vp8dx_set_reference(ctx->pbi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8_get_reference(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + + vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); + + if (data) + { + vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; + YV12_BUFFER_CONFIG sd; + + image2yuvconfig(&frame->img, &sd); + + vp8dx_get_reference(ctx->pbi, frame->frame_type, &sd); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +} + +static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx, + int ctr_id, + va_list args) +{ + vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); +#if CONFIG_POSTPROC + + if (data) + { + ctx->postproc_cfg_set = 1; + ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data); + return VPX_CODEC_OK; + } + else + return VPX_CODEC_INVALID_PARAM; + +#else + return VPX_CODEC_INCAPABLE; +#endif +} + + +vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] = +{ + {VP8_SET_REFERENCE, vp8_set_reference}, + {VP8_COPY_REFERENCE, vp8_get_reference}, + {VP8_SET_POSTPROC, vp8_set_postproc}, + { -1, NULL}, +}; + + +#ifndef VERSION_STRING +#define VERSION_STRING +#endif +vpx_codec_iface_t vpx_codec_vp8_dx_algo = +{ + "vpx Technologies VP8 Decoder" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC, + /* vpx_codec_caps_t caps; */ + vp8_init, /* vpx_codec_init_fn_t init; */ + vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */ + vp8_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + vp8_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */ + vp8_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */ + { + vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */ + vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */ + vp8_decode, /* vpx_codec_decode_fn_t decode; */ + vp8_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */ + }, + {NOT_IMPLEMENTED} /* encoder functions */ +}; + +/* + * BEGIN BACKWARDS COMPATIBILITY SHIM. + */ +vpx_codec_iface_t vpx_codec_vp8_algo = +{ + "vpx Technologies VP8 Decoder (Deprecated API)" VERSION_STRING, + VPX_CODEC_INTERNAL_ABI_VERSION, + VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC, + /* vpx_codec_caps_t caps; */ + vp8_init, /* vpx_codec_init_fn_t init; */ + vp8_destroy, /* vpx_codec_destroy_fn_t destroy; */ + vp8_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ + vp8_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */ + vp8_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */ + { + vp8_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */ + vp8_get_si, /* vpx_codec_get_si_fn_t get_si; */ + vp8_decode, /* vpx_codec_decode_fn_t decode; */ + vp8_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */ + }, + {NOT_IMPLEMENTED} /* encoder functions */ +};
diff --git a/vp8/vp8cx.h b/vp8/vp8cx.h new file mode 100644 index 0000000..dd48c07 --- /dev/null +++ b/vp8/vp8cx.h
@@ -0,0 +1,261 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/*!\defgroup vp8_encoder WebM VP8 Encoder + * \ingroup vp8 + * + * @{ + */ +#include "vp8.h" + +/*!\file vp8cx.h + * \brief Provides definitions for using the VP8 encoder algorithm within the + * vpx Codec Interface. + */ +#ifndef VP8CX_H +#define VP8CX_H +#include "vpx_codec_impl_top.h" + +/*!\brief Algorithm interface for VP8 + * + * This interface provides the capability to encode raw VP8 streams, as would + * be found in AVI files. + */ +extern vpx_codec_iface_t vpx_codec_vp8_cx_algo; + + +/* + * Algorithm Flags + */ + +/*!\brief Don't reference the last frame + * + * When this flag is set, the encoder will not use the last frame as a + * predictor. When not set, the encoder will choose whether to use the + * last frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_LAST (1<<16) + + +/*!\brief Don't reference the golden frame + * + * When this flag is set, the encoder will not use the golden frame as a + * predictor. When not set, the encoder will choose whether to use the + * golden frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_GF (1<<17) + + +/*!\brief Don't reference the alternate reference frame + * + * When this flag is set, the encoder will not use the alt ref frame as a + * predictor. When not set, the encoder will choose whether to use the + * alt ref frame or not automatically. + */ +#define VP8_EFLAG_NO_REF_ARF (1<<21) + + +/*!\brief Don't update the last frame + * + * When this flag is set, the encoder will not update the last frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_LAST (1<<18) + + +/*!\brief Don't update the golden frame + * + * When this flag is set, the encoder will not update the golden frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_GF (1<<22) + + +/*!\brief Don't update the alternate reference frame + * + * When this flag is set, the encoder will not update the alt ref frame with + * the contents of the current frame. + */ +#define VP8_EFLAG_NO_UPD_ARF (1<<23) + + +/*!\brief Force golden frame update + * + * When this flag is set, the encoder copy the contents of the current frame + * to the golden frame buffer. + */ +#define VP8_EFLAG_FORCE_GF (1<<19) + + +/*!\brief Force alternate reference frame update + * + * When this flag is set, the encoder copy the contents of the current frame + * to the alternate reference frame buffer. + */ +#define VP8_EFLAG_FORCE_ARF (1<<24) + + +/*!\brief Disable entropy update + * + * When this flag is set, the encoder will not update its internal entropy + * model based on the entropy of this frame. + */ +#define VP8_EFLAG_NO_UPD_ENTROPY (1<<20) + + +/*!\brief VP8 encoder control functions + * + * The set of macros define the control functions of VP8 encoder interface + */ +enum vp8e_enc_control_id +{ + VP8E_UPD_ENTROPY = 5, /**< control function to set mode of entropy update in encoder */ + VP8E_UPD_REFERENCE, /**< control function to set reference update mode in encoder */ + VP8E_USE_REFERENCE, /**< control function to set which reference frame encoder can use */ + VP8E_SET_ROI_MAP, /**< control function to pass an ROI map to encoder */ + VP8E_SET_ACTIVEMAP, /**< control function to pass an Active map to encoder */ + VP8E_SET_SCALEMODE = 11, /**< control function to set encoder scaling mode */ + VP8E_SET_CPUUSED = 13, /**< control function to set vp8 encoder cpuused */ + VP8E_SET_ENABLEAUTOALTREF, /**< control function to enable vp8 to automatic set and use altref frame */ + VP8E_SET_NOISE_SENSITIVITY, /**< control function to set noise sensitivity */ + VP8E_SET_SHARPNESS, /**< control function to set sharpness */ + VP8E_SET_STATIC_THRESHOLD, /**< control function to set the threshold for macroblocks treated static */ + VP8E_SET_TOKEN_PARTITIONS, /**< control function to set the number of token partitions */ + VP8E_GET_LAST_QUANTIZER, /**< return the quantizer chosen by the + encoder for the last frame using the internal + scale */ + VP8E_GET_LAST_QUANTIZER_64, /**< return the quantizer chosen by the + encoder for the last frame, using the 0..63 + scale as used by the rc_*_quantizer config + parameters */ + VP8E_SET_ARNR_MAXFRAMES, /**< control function to set the max number of frames blurred creating arf*/ + VP8E_SET_ARNR_STRENGTH , /**< control function to set the filter strength for the arf */ + VP8E_SET_ARNR_TYPE , /**< control function to set the type of filter to use for the arf*/ +} ; + +/*!\brief vpx 1-D scaling mode + * + * This set of constants define 1-D vpx scaling modes + */ +typedef enum vpx_scaling_mode_1d +{ + VP8E_NORMAL = 0, + VP8E_FOURFIVE = 1, + VP8E_THREEFIVE = 2, + VP8E_ONETWO = 3 +} VPX_SCALING_MODE; + + +/*!\brief vpx region of interest map + * + * These defines the data structures for the region of interest map + * + */ + +typedef struct vpx_roi_map +{ + unsigned char *roi_map; /**< specify an id between 0 and 3 for each 16x16 region within a frame */ + unsigned int rows; /**< number of rows */ + unsigned int cols; /**< number of cols */ + int delta_q[4]; /**< quantizer delta [-64, 64] off baseline for regions with id between 0 and 3*/ + int delta_lf[4]; /**< loop filter strength delta [-32, 32] for regions with id between 0 and 3 */ + unsigned int static_threshold[4];/**< threshold for region to be treated as static */ +} vpx_roi_map_t; + +/*!\brief vpx active region map + * + * These defines the data structures for active region map + * + */ + + +typedef struct vpx_active_map +{ + unsigned char *active_map; /**< specify an on (1) or off (0) each 16x16 region within a frame */ + unsigned int rows; /**< number of rows */ + unsigned int cols; /**< number of cols */ +} vpx_active_map_t; + +/*!\brief vpx image scaling mode + * + * This defines the data structure for image scaling mode + * + */ +typedef struct vpx_scaling_mode +{ + VPX_SCALING_MODE h_scaling_mode; /**< horizontal scaling mode */ + VPX_SCALING_MODE v_scaling_mode; /**< vertical scaling mode */ +} vpx_scaling_mode_t; + +/*!\brief VP8 encoding mode + * + * This defines VP8 encoding mode + * + */ +typedef enum +{ + VP8_BEST_QUALITY_ENCODING, + VP8_GOOD_QUALITY_ENCODING, + VP8_REAL_TIME_ENCODING +} vp8e_encoding_mode; + +/*!\brief VP8 token partition mode + * + * This defines VP8 partitioning mode for compressed data, i.e., the number of + * sub-streams in the bitstream. Used for parallelized decoding. + * + */ + +typedef enum +{ + VP8_ONE_TOKENPARTITION = 0, + VP8_TWO_TOKENPARTITION = 1, + VP8_FOUR_TOKENPARTITION = 2, + VP8_EIGHT_TOKENPARTITION = 3, +} vp8e_token_partitions; + + +/*!\brief VP8 encoder control function parameter type + * + * Defines the data types that VP8E control functions take. Note that + * additional common controls are defined in vp8.h + * + */ + + +/* These controls have been deprecated in favor of the flags parameter to + * vpx_codec_encode(). See the definition of VP8_EFLAG_* above. + */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_ENTROPY, int) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_UPD_REFERENCE, int) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_USE_REFERENCE, int) + +VPX_CTRL_USE_TYPE(VP8E_SET_ROI_MAP, vpx_roi_map_t *) +VPX_CTRL_USE_TYPE(VP8E_SET_ACTIVEMAP, vpx_active_map_t *) +VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *) + +VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int) +VPX_CTRL_USE_TYPE(VP8E_SET_ENABLEAUTOALTREF, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_NOISE_SENSITIVITY, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_SHARPNESS, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_STATIC_THRESHOLD, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_TOKEN_PARTITIONS, vp8e_token_partitions) + +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_MAXFRAMES, unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_STRENGTH , unsigned int) +VPX_CTRL_USE_TYPE(VP8E_SET_ARNR_TYPE , unsigned int) + + +VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER, int *) +VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *) + +/*! @} - end defgroup vp8_encoder */ +#include "vpx_codec_impl_bottom.h" +#endif
diff --git a/vp8/vp8cx.mk b/vp8/vp8cx.mk new file mode 100644 index 0000000..e7e7663 --- /dev/null +++ b/vp8/vp8cx.mk
@@ -0,0 +1,104 @@ +## +## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license and patent +## grant that can be found in the LICENSE file in the root of the source +## tree. All contributing project authors may be found in the AUTHORS +## file in the root of the source tree. +## + + +include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk +VP8_CX_SRCS-yes += $(VP8_COMMON_SRCS-yes) +VP8_CX_SRCS-no += $(VP8_COMMON_SRCS-no) +VP8_CX_SRCS_REMOVE-yes += $(VP8_COMMON_SRCS_REMOVE-yes) +VP8_CX_SRCS_REMOVE-no += $(VP8_COMMON_SRCS_REMOVE-no) + +ifeq ($(ARCH_ARM),yes) + include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8cx_arm.mk +endif + +VP8_CX_SRCS-yes += vp8cx.h vp8e.h vp8_cx_iface.c + +# encoder +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += algo/vpx_ref/cpu_id/include +#INCLUDES += common +#INCLUDES += encoder + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)encoder + +VP8_CX_SRCS-yes += encoder/bitstream.c +VP8_CX_SRCS-yes += encoder/boolhuff.c +VP8_CX_SRCS-yes += encoder/dct.c +VP8_CX_SRCS-yes += encoder/encodeframe.c +VP8_CX_SRCS-yes += encoder/encodeintra.c +VP8_CX_SRCS-yes += encoder/encodemb.c +VP8_CX_SRCS-yes += encoder/encodemv.c +VP8_CX_SRCS-yes += encoder/ethreading.c +VP8_CX_SRCS-yes += encoder/firstpass.c +VP8_CX_SRCS-yes += encoder/generic/csystemdependent.c +VP8_CX_SRCS-yes += encoder/block.h +VP8_CX_SRCS-yes += encoder/boolhuff.h +VP8_CX_SRCS-yes += encoder/bitstream.h +VP8_CX_SRCS-yes += encoder/dct.h +VP8_CX_SRCS-yes += encoder/encodeintra.h +VP8_CX_SRCS-yes += encoder/encodemb.h +VP8_CX_SRCS-yes += encoder/encodemv.h +VP8_CX_SRCS-yes += encoder/firstpass.h +VP8_CX_SRCS-yes += encoder/mcomp.h +VP8_CX_SRCS-yes += encoder/modecosts.h +VP8_CX_SRCS-yes += encoder/onyx_int.h +VP8_CX_SRCS-yes += encoder/pickinter.h +VP8_CX_SRCS-yes += encoder/psnr.h +VP8_CX_SRCS-yes += encoder/quantize.h +VP8_CX_SRCS-yes += encoder/ratectrl.h +VP8_CX_SRCS-yes += encoder/rdopt.h +VP8_CX_SRCS-yes += encoder/tokenize.h +VP8_CX_SRCS-yes += encoder/treewriter.h +VP8_CX_SRCS-yes += encoder/variance.h +VP8_CX_SRCS-yes += encoder/mcomp.c +VP8_CX_SRCS-yes += encoder/modecosts.c +VP8_CX_SRCS-yes += encoder/onyx_if.c +VP8_CX_SRCS-yes += encoder/pickinter.c +VP8_CX_SRCS-yes += encoder/picklpf.c +VP8_CX_SRCS-yes += encoder/psnr.c +VP8_CX_SRCS-yes += encoder/quantize.c +VP8_CX_SRCS-yes += encoder/ratectrl.c +VP8_CX_SRCS-yes += encoder/rdopt.c +VP8_CX_SRCS-yes += encoder/sad_c.c +VP8_CX_SRCS-yes += encoder/ssim.c +VP8_CX_SRCS-yes += encoder/tokenize.c +VP8_CX_SRCS-yes += encoder/treewriter.c +VP8_CX_SRCS-yes += encoder/variance_c.c + +ifeq ($(CONFIG_REALTIME_ONLY),yes) +VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c +endif + +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/encodemb_x86.h +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/dct_x86.h +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/mcomp_x86.h +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/variance_x86.h +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/x86_csystemdependent.c +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/variance_mmx.c +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/variance_impl_mmx.asm +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/sad_mmx.asm +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/dct_mmx.asm +VP8_CX_SRCS-$(HAVE_MMX) += encoder/x86/subtract_mmx.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/variance_sse2.c +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/variance_impl_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/sad_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/dct_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE2) += encoder/x86/fwalsh_sse2.asm +VP8_CX_SRCS-$(HAVE_SSE3) += encoder/x86/sad_sse3.asm +VP8_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/sad_ssse3.asm +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/quantize_mmx.asm +VP8_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/encodeopt.asm + +VP8_CX_SRCS-yes := $(filter-out $(VP8_CX_SRCS_REMOVE-yes),$(VP8_CX_SRCS-yes)) + +INSTALL-LIBS-yes += include/vp8.h include/vp8e.h include/vp8cx.h
diff --git a/vp8/vp8cx_arm.mk b/vp8/vp8cx_arm.mk new file mode 100644 index 0000000..f0753d9 --- /dev/null +++ b/vp8/vp8cx_arm.mk
@@ -0,0 +1,64 @@ +## +## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license and patent +## grant that can be found in the LICENSE file in the root of the source +## tree. All contributing project authors may be found in the AUTHORS +## file in the root of the source tree. +## + + +#VP8_CX_SRCS list is modified according to different platforms. + +#File list for arm +# encoder +VP8_CX_SRCS-$(HAVE_ARMV6) += encoder/arm/csystemdependent.c + +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/encodemb_arm.c +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/quantize_arm.c +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/picklpf_arm.c +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/boolhuff_arm.c +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/mcomp_arm.c + +VP8_CX_SRCS_REMOVE-$(HAVE_ARMV6) += encoder/generic/csystemdependent.c +VP8_CX_SRCS_REMOVE-$(HAVE_ARMV7) += encoder/boolhuff.c +VP8_CX_SRCS_REMOVE-$(HAVE_ARMV7) += encoder/mcomp.c + +#File list for armv6 +# encoder +VP8_CX_SRCS-$(HAVE_ARMV6) += encoder/arm/armv6/walsh_v6$(ASM) + +#File list for neon +# encoder +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/fastfdct4x4_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/fastfdct8x4_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/fastquantizeb_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/sad8_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/sad16_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/shortfdct_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/subtract_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/variance_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_mse16x16_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_subpixelvariance8x8_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_subpixelvariance16x16_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_subpixelvariance16x16s_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_memcpy_neon$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_packtokens_armv7$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_packtokens_mbrow_armv7$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_packtokens_partitions_armv7$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/boolhuff_armv7$(ASM) +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/neon/vp8_shortwalsh4x4_neon$(ASM) + +VP8_CX_SRCS-$(HAVE_ARMV7) += encoder/arm/vpx_vp8_enc_asm_offsets.c + +# +# Rule to extract assembly constants from C sources +# +ifeq ($(ARCH_ARM),yes) +vpx_vp8_enc_asm_offsets.asm: obj_int_extract +vpx_vp8_enc_asm_offsets.asm: $(VP8_PREFIX)encoder/arm/vpx_vp8_enc_asm_offsets.c.o + ./obj_int_extract rvds $< $(ADS2GAS) > $@ +OBJS-yes += $(VP8_PREFIX)encoder/arm/vpx_vp7_enc_asm_offsets.c.o +CLEAN-OBJS += vpx_vp8_enc_asm_offsets.asm +$(filter %$(ASM).o,$(OBJS-yes)): vpx_vp8_enc_asm_offsets.asm +endif
diff --git a/vp8/vp8dx.h b/vp8/vp8dx.h new file mode 100644 index 0000000..7310b3b --- /dev/null +++ b/vp8/vp8dx.h
@@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +#include "vp8.h" + +/*!\defgroup vp8_decoder WebM VP8 Decoder + * \ingroup vp8 + * + * @{ + */ +/*!\file vp8dx.h + * \brief Provides definitions for using the VP8 algorithm within the vpx Decoder + * interface. + */ +#ifndef VP8DX_H +#define VP8DX_H +#include "vpx_codec_impl_top.h" + +/*!\brief Algorithm interface for VP8 + * + * This interface provides the capability to decode raw VP8 streams, as would + * be found in AVI files and other non-Flash uses. + */ +extern vpx_codec_iface_t vpx_codec_vp8_dx_algo; + +/* Include controls common to both the encoder and decoder */ +#include "vp8.h" + + +/*! @} - end defgroup vp8_decoder */ + + +#include "vpx_codec_impl_bottom.h" +#endif
diff --git a/vp8/vp8dx.mk b/vp8/vp8dx.mk new file mode 100644 index 0000000..e6af543 --- /dev/null +++ b/vp8/vp8dx.mk
@@ -0,0 +1,76 @@ +## +## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license and patent +## grant that can be found in the LICENSE file in the root of the source +## tree. All contributing project authors may be found in the AUTHORS +## file in the root of the source tree. +## + + +include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk +VP8_DX_SRCS-yes += $(VP8_COMMON_SRCS-yes) +VP8_DX_SRCS-no += $(VP8_COMMON_SRCS-no) +VP8_DX_SRCS_REMOVE-yes += $(VP8_COMMON_SRCS_REMOVE-yes) +VP8_DX_SRCS_REMOVE-no += $(VP8_COMMON_SRCS_REMOVE-no) + +ifeq ($(ARCH_ARM),yes) + include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8dx_arm.mk +endif + +VP8_DX_SRCS-yes += vp8dx.h vp8_dx_iface.c + +CFLAGS+=-I$(SRC_PATH_BARE)/$(VP8_PREFIX)decoder + + +# common +#define ARM +#define DISABLE_THREAD +#define INLINE=__forceinline + +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += decoder + + + +# decoder +#define ARM +#define DISABLE_THREAD +#define INLINE=__forceinline + +#INCLUDES += algo/vpx_common/vpx_mem/include +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += common +#INCLUDES += decoder + +VP8_DX_SRCS-yes += decoder/dboolhuff.c +VP8_DX_SRCS-yes += decoder/decodemv.c +VP8_DX_SRCS-yes += decoder/decodframe.c +VP8_DX_SRCS-yes += decoder/demode.c +VP8_DX_SRCS-yes += decoder/dequantize.c +VP8_DX_SRCS-yes += decoder/detokenize.c +VP8_DX_SRCS-yes += decoder/generic/dsystemdependent.c +VP8_DX_SRCS-yes += decoder/dboolhuff.h +VP8_DX_SRCS-yes += decoder/decodemv.h +VP8_DX_SRCS-yes += decoder/decoderthreading.h +VP8_DX_SRCS-yes += decoder/demode.h +VP8_DX_SRCS-yes += decoder/dequantize.h +VP8_DX_SRCS-yes += decoder/detokenize.h +VP8_DX_SRCS-yes += decoder/onyxd_int.h +VP8_DX_SRCS-yes += decoder/treereader.h +VP8_DX_SRCS-yes += decoder/onyxd_if.c +VP8_DX_SRCS-yes += decoder/threading.c + +VP8_DX_SRCS-yes := $(filter-out $(VP8_DX_SRCS_REMOVE-yes),$(VP8_DX_SRCS-yes)) + +INSTALL-LIBS-yes += include/vp8.h include/vp8dx.h + +VP8_DX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += decoder/x86/dequantize_x86.h +VP8_DX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += decoder/x86/x86_dsystemdependent.c +VP8_DX_SRCS-$(HAVE_MMX) += decoder/x86/dequantize_mmx.asm
diff --git a/vp8/vp8dx_arm.mk b/vp8/vp8dx_arm.mk new file mode 100644 index 0000000..1b4a7ec --- /dev/null +++ b/vp8/vp8dx_arm.mk
@@ -0,0 +1,44 @@ +## +## Copyright (c) 2010 The VP8 project authors. All Rights Reserved. +## +## Use of this source code is governed by a BSD-style license and patent +## grant that can be found in the LICENSE file in the root of the source +## tree. All contributing project authors may be found in the AUTHORS +## file in the root of the source tree. +## + + +#VP8_DX_SRCS list is modified according to different platforms. + +#File list for arm +# decoder +#VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/decodframe_arm.c +VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/dequantize_arm.c +VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/dsystemdependent.c + +#VP8_DX_SRCS_REMOVE-$(HAVE_ARMV6) += decoder/decodframe.c +VP8_DX_SRCS_REMOVE-$(HAVE_ARMV6) += decoder/dequantize.c +VP8_DX_SRCS_REMOVE-$(HAVE_ARMV6) += decoder/generic/dsystemdependent.c + +#File list for armv6 +# decoder +VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/armv6/dequantdcidct_v6$(ASM) +VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/armv6/dequantidct_v6$(ASM) +VP8_DX_SRCS-$(HAVE_ARMV6) += decoder/arm/armv6/dequantize_v6$(ASM) + +#File list for neon +# decoder +VP8_DX_SRCS-$(HAVE_ARMV7) += decoder/arm/neon/dequantdcidct_neon$(ASM) +VP8_DX_SRCS-$(HAVE_ARMV7) += decoder/arm/neon/dequantidct_neon$(ASM) +VP8_DX_SRCS-$(HAVE_ARMV7) += decoder/arm/neon/dequantizeb_neon$(ASM) + + +#for new token test +ifeq ($(ARCH_ARM),yes) +VP8_DX_SRCS-$(CONFIG_NEW_TOKENS) += decoder/arm/detokenize_arm_sjl.c +VP8_DX_SRCS-$(CONFIG_NEW_TOKENS) += decoder/arm/detokenize_arm_v6$(ASM) +VP8_DX_SRCS-$(CONFIG_NEW_TOKENS) += decoder/onyxd_if_sjl.c + +VP8_DX_SRCS_REMOVE-$(CONFIG_NEW_TOKENS) += decoder/arm/detokenize_arm.c +VP8_DX_SRCS_REMOVE-$(CONFIG_NEW_TOKENS) += decoder/onyxd_if.c +endif
diff --git a/vp8/vp8e.h b/vp8/vp8e.h new file mode 100644 index 0000000..a90aa2a --- /dev/null +++ b/vp8/vp8e.h
@@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license and patent + * grant that can be found in the LICENSE file in the root of the source + * tree. All contributing project authors may be found in the AUTHORS + * file in the root of the source tree. + */ + + +/* This file contains backwards compatibility stubs for applications using + * the VP8 version 1.0 API. + */ +#ifndef VP8E_H +#define VP8E_H +#include "vpx_codec_impl_top.h" + +#if defined(VPX_CODEC_DISABLE_COMPAT) && VPX_CODEC_DISABLE_COMPAT +#error "Backwards compatibility disabled: don't include vp8e.h" +#endif + +#include "vp8cx.h" +DECLSPEC_DEPRECATED extern vpx_codec_iface_t vpx_enc_vp8_algo DEPRECATED; + + +enum +{ + VP8E_SET_REFERENCE = VP8_SET_REFERENCE, + VP8E_COPY_REFERENCE = VP8_COPY_REFERENCE, + VP8E_SET_PREVIEWPP = VP8_SET_POSTPROC, + VP8E_SET_FLUSHFLAG = 4, + VP8E_SET_FRAMETYPE = 10, + VP8E_SET_ENCODING_MODE = 12 +}; + +#define NORMAL_FRAME (0) +#define KEY_FRAME (1) + +/* Change VP8E to VP8 to get the undeprecated version of these (defined in + * vp8.h) + */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_COPY_REFERENCE, vpx_ref_frame_t *) +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_PREVIEWPP, vp8_postproc_cfg_t *) + + +/* Flush is done by calling vpx_codec_encode with a NULL input image. */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_FLUSHFLAG, int) + + +/* Frame type is set with a flag to vpx_codec_control. See VPX_EFLAG_FORCE_KF + */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_FRAMETYPE, int) + + +/* This control has been deprecated in favor of the duration parameter to + * vpx_codec_encode(). Use the #VPX_DL_REALTIME, #VPX_DL_GOOD_QUALITY, + * #VPX_DL_BEST_QUALITY constants to that parameter instead. + */ +VPX_CTRL_USE_TYPE_DEPRECATED(VP8E_SET_ENCODING_MODE, vp8e_encoding_mode) +#include "vpx_codec_impl_bottom.h" +#endif