From 68aa70a49a81079443b8746b75b8728052c68ad4 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Wed, 9 Oct 2013 15:31:27 +0300 Subject: [PATCH 01/19] Add tests for calculating sad outside frame. --- .../HEVC_encoder_tests.vcxproj | 29 +++- .../HEVC_encoder_tests.vcxproj.filters | 6 + build/HEVC_interface/HEVC_interface.vcxproj | 14 +- tests/sad_tests.cpp | 148 ++++++++++++++++++ tests/sad_tests.h | 6 + tests/tests_main.c | 2 + 6 files changed, 194 insertions(+), 11 deletions(-) create mode 100644 tests/sad_tests.cpp create mode 100644 tests/sad_tests.h diff --git a/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj b/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj index a3ddd3b8..1841f3a6 100644 --- a/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj +++ b/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj @@ -18,7 +18,6 @@ x64 - {eea3bdd1-8a08-41c1-ba57-e05d5c2cd8ff} @@ -29,9 +28,7 @@ Win32Proj HEVC_encoder_tests - - true @@ -44,9 +41,7 @@ false - - @@ -64,16 +59,36 @@ - + + + $(TargetPath) + + + + + $(TargetPath) + + + + + $(TargetPath) + + + + + $(TargetPath) + + + + - diff --git a/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj.filters b/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj.filters index 852ea854..a06cae76 100644 --- a/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj.filters +++ b/build/HEVC_encoder_tests/HEVC_encoder_tests.vcxproj.filters @@ -24,10 +24,16 @@ Source Files + + Source Files + Header Files + + Header Files + \ No newline at end of file diff --git a/build/HEVC_interface/HEVC_interface.vcxproj b/build/HEVC_interface/HEVC_interface.vcxproj index a30c428d..41374287 100644 --- a/build/HEVC_interface/HEVC_interface.vcxproj +++ b/build/HEVC_interface/HEVC_interface.vcxproj @@ -23,9 +23,7 @@ Win32Proj HEVC_interface - - true @@ -38,9 +36,7 @@ false - - @@ -70,6 +66,16 @@ HEVC_encoder + + + HEVC_encoder_tests.exe + + + + + Run tests. + + {eea3bdd1-8a08-41c1-ba57-e05d5c2cd8ff} diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp new file mode 100644 index 00000000..1c84a6e1 --- /dev/null +++ b/tests/sad_tests.cpp @@ -0,0 +1,148 @@ +#include "seatest.h" + +#include + +#include "picture.h" + +////////////////////////////////////////////////////////////////////////// +// EXTERNAL FUNCTIONS +unsigned get_block_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height); + +////////////////////////////////////////////////////////////////////////// +// DEFINES +#define TEST_SAD(X, Y) get_block_sad(g_pic, g_ref, 0, 0, (X), (Y), 8, 8) + +////////////////////////////////////////////////////////////////////////// +// GLOBALS +const uint8_t ref_data[64] = { + 1,2,2,2,2,2,2,3, + 4,5,5,5,5,5,5,6, + 4,5,5,5,5,5,5,6, + 4,5,5,5,5,5,5,6, + 4,5,5,5,5,5,5,6, + 4,5,5,5,5,5,5,6, + 4,5,5,5,5,5,5,6, + 7,8,8,8,8,8,8,9 +}; + +const uint8_t pic_data[64] = { + 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 +}; + +picture *g_pic = 0; +picture *g_ref = 0; + +////////////////////////////////////////////////////////////////////////// +// SETUP, TEARDOWN AND HELPER FUNCTIONS +void sad_setup(void) +{ + g_pic = picture_init(8, 8, 1, 1); + memcpy(g_pic->y_data, pic_data, 64); + + g_ref = picture_init(8, 8, 1, 1); + memcpy(g_ref->y_data, ref_data, 64); +} + +void sad_teardown(void) +{ + free(g_pic); g_pic = 0; + free(g_ref); g_ref = 0; +} + +////////////////////////////////////////////////////////////////////////// +// TESTS +void test_topleft(void) +{ + assert_ulong_equal( + 1*(5*5) + (2+4)*(3*5) + 5*(3*3) - 64, + TEST_SAD(-4, -4)); +} + +void test_top(void) +{ + assert_ulong_equal( + 1*5 + 2*(6*5) + 3*5 + (4+6)*3 + 5*(6*3) - 64, + TEST_SAD(0, -4)); +} + +void test_topright(void) +{ + assert_ulong_equal( + 3*(5*5) + (2+6)*(3*5) + 5*(3*3) - 64, + TEST_SAD(4, -4)); +} + +void test_left(void) +{ + assert_ulong_equal( + 1*5 + 4*(6*5) + 7*5 + (2+8)*3 + 5*(6*3) - 64, + TEST_SAD(-4, 0)); +} + +void test_no_offset(void) +{ + assert_ulong_equal( + (1+3+7+9) + (2+4+6+8)*6 + 6*(6*5) - 64, + TEST_SAD(0, 0)); +} + +void test_right(void) +{ + assert_ulong_equal( + (3+9)*5 + 6*(5*6) + (2+8)*3 + 5*(6*3) - 64, + TEST_SAD(4, 0)); +} + +void test_bottomleft(void) +{ + assert_ulong_equal( + 7*(5*5) + (4+8)*(3*5) + 5*(3*3) - 64, + TEST_SAD(-4, -4)); +} + +void test_bottom(void) +{ + assert_ulong_equal( + (7+9)*5 + 8*(6*5) + (4+6)*3 + 5*(6*3) - 64, + TEST_SAD(0, -4)); +} + +void test_bottomright(void) +{ + assert_ulong_equal( + 9*(5*5) + (6+8)*(3*5) + 5*(3*3) - 64, + TEST_SAD(-4, -4)); +} + +////////////////////////////////////////////////////////////////////////// +// TEST FIXTURES +void sad_tests(void) +{ + test_fixture_start(); + fixture_setup(sad_setup); + + run_test(test_topleft); + run_test(test_top); + run_test(test_topright); + + run_test(test_left); + run_test(test_no_offset); + run_test(test_right); + + run_test(test_bottomleft); + run_test(test_bottom); + run_test(test_bottomright); + + fixture_teardown(sad_teardown); + test_fixture_end(); +} + diff --git a/tests/sad_tests.h b/tests/sad_tests.h new file mode 100644 index 00000000..6cdcd27b --- /dev/null +++ b/tests/sad_tests.h @@ -0,0 +1,6 @@ +#ifndef SAD_TESTS_H_ +#define SAD_TESTS_H_ + +void sad_tests(void); + +#endif diff --git a/tests/tests_main.c b/tests/tests_main.c index 489e2d02..56074dc7 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -1,11 +1,13 @@ #include "seatest.h" #include "picture_list_tests.h" +#include "sad_tests.h" void all_tests(void) { picture_list_tests(); + sad_tests(); } int main() From ea30bf0126e00364dfd5010c3645135d0b9751a2 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Wed, 9 Oct 2013 15:37:21 +0300 Subject: [PATCH 02/19] Fix SAD calculation to return correct value in non-overlapping case. --- src/search.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.c b/src/search.c index 5981bd07..e24f787d 100644 --- a/src/search.c +++ b/src/search.c @@ -57,7 +57,7 @@ unsigned get_block_sad(picture *pic, picture *ref, int width = pic->width; int height = pic->height; - unsigned result = 1; // Start from 1 so result is never 0. + unsigned result = 0; // 0 means invalid, for now. if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; From 24d9fd7c053be4bd66f305da6fa8c1d18798fa11 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 14:04:19 +0300 Subject: [PATCH 03/19] Fix wrong index in sad tests. --- tests/sad_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index 1c84a6e1..b1be4bfb 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -106,21 +106,21 @@ void test_bottomleft(void) { assert_ulong_equal( 7*(5*5) + (4+8)*(3*5) + 5*(3*3) - 64, - TEST_SAD(-4, -4)); + TEST_SAD(-4, 4)); } void test_bottom(void) { assert_ulong_equal( (7+9)*5 + 8*(6*5) + (4+6)*3 + 5*(6*3) - 64, - TEST_SAD(0, -4)); + TEST_SAD(0, 4)); } void test_bottomright(void) { assert_ulong_equal( 9*(5*5) + (6+8)*(3*5) + 5*(3*3) - 64, - TEST_SAD(-4, -4)); + TEST_SAD(-4, 4)); } ////////////////////////////////////////////////////////////////////////// From 2b4ca9b3e520969de753d5a4a5c5a320c1b4b09a Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 14:31:59 +0300 Subject: [PATCH 04/19] Remove tests as post build event from main project. It wasn't supposed to be there yet. --- build/HEVC_interface/HEVC_interface.vcxproj | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/build/HEVC_interface/HEVC_interface.vcxproj b/build/HEVC_interface/HEVC_interface.vcxproj index 41374287..2820b13e 100644 --- a/build/HEVC_interface/HEVC_interface.vcxproj +++ b/build/HEVC_interface/HEVC_interface.vcxproj @@ -67,14 +67,10 @@ HEVC_encoder - - HEVC_encoder_tests.exe - + - - Run tests. - + From 356a0e8a149820915863820b73e0467ea3003e65 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 15:16:14 +0300 Subject: [PATCH 05/19] Change SAD-test offset. Using 3 instead of 4 avoids having symmetric negation of the offset, like -4 and +4. It also makes the expected result easier to calculate by hand. --- tests/sad_tests.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index b1be4bfb..21240ec6 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -63,64 +63,64 @@ void sad_teardown(void) void test_topleft(void) { assert_ulong_equal( - 1*(5*5) + (2+4)*(3*5) + 5*(3*3) - 64, - TEST_SAD(-4, -4)); + 1*(4*4) + (2+4)*(4*4) + 5*(4*4) - 64, + TEST_SAD(-3, -3)); } void test_top(void) { assert_ulong_equal( - 1*5 + 2*(6*5) + 3*5 + (4+6)*3 + 5*(6*3) - 64, - TEST_SAD(0, -4)); + (1+3)*4 + 2*(6*4) + (4+6)*4 + 5*(6*4) - 64, + TEST_SAD(0, -3)); } void test_topright(void) { assert_ulong_equal( - 3*(5*5) + (2+6)*(3*5) + 5*(3*3) - 64, - TEST_SAD(4, -4)); + 3*(4*4) + (2+6)*(4*4) + 5*(4*4) - 64, + TEST_SAD(3, -3)); } void test_left(void) { assert_ulong_equal( - 1*5 + 4*(6*5) + 7*5 + (2+8)*3 + 5*(6*3) - 64, - TEST_SAD(-4, 0)); + (1+7)*4 + 4*(6*4) + (2+8)*4 + 5*(6*4) - 64, + TEST_SAD(-3, 0)); } void test_no_offset(void) { assert_ulong_equal( - (1+3+7+9) + (2+4+6+8)*6 + 6*(6*5) - 64, + (1+3+7+9) + (2+4+6+8)*6 + 5*(6*6) - 64, TEST_SAD(0, 0)); } void test_right(void) { assert_ulong_equal( - (3+9)*5 + 6*(5*6) + (2+8)*3 + 5*(6*3) - 64, - TEST_SAD(4, 0)); + (3+9)*4 + 6*(4*6) + (2+8)*4 + 5*(6*4) - 64, + TEST_SAD(3, 0)); } void test_bottomleft(void) { assert_ulong_equal( - 7*(5*5) + (4+8)*(3*5) + 5*(3*3) - 64, - TEST_SAD(-4, 4)); + 7*(4*4) + (4+8)*(4*4) + 5*(4*4) - 64, + TEST_SAD(-3, 3)); } void test_bottom(void) { assert_ulong_equal( - (7+9)*5 + 8*(6*5) + (4+6)*3 + 5*(6*3) - 64, - TEST_SAD(0, 4)); + (7+9)*4 + 8*(6*4) + (4+6)*4 + 5*(6*4) - 64, + TEST_SAD(0, 3)); } void test_bottomright(void) { assert_ulong_equal( - 9*(5*5) + (6+8)*(3*5) + 5*(3*3) - 64, - TEST_SAD(-4, 4)); + 9*(4*4) + (6+8)*(4*4) + 5*(4*4) - 64, + TEST_SAD(-3, 3)); } ////////////////////////////////////////////////////////////////////////// From 684f6d548c89d8a4fe69967bea931a87cbc80074 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 16:11:07 +0300 Subject: [PATCH 06/19] Start adding sad calculation outside frame. Works for top-left corner. 2/9 tests pass. --- src/search.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/src/search.c b/src/search.c index e24f787d..ecdac9f4 100644 --- a/src/search.c +++ b/src/search.c @@ -36,6 +36,51 @@ && (x) + (block_width) <= (width) \ && (y) + (block_height) <= (height)) +unsigned corner_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned char ref = *ref_data; + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref); + } + } + + return sad; +} + +unsigned vertical_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref_data[x]); + } + } + + return sad; +} + +unsigned horizontal_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref_data[y * width]); + } + } + + return sad; +} /** * \brief Get Sum of Absolute Differences (SAD) between two blocks in two @@ -56,15 +101,53 @@ unsigned get_block_sad(picture *pic, picture *ref, uint8_t *pic_data, *ref_data; int width = pic->width; int height = pic->height; + int left = ref_x < 0; + int right = ref_x + block_width > width; + int top = ref_y < 0; + int bottom = ref_y + block_height > height; unsigned result = 0; // 0 means invalid, for now. - if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; + //if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; - pic_data = &pic->y_data[pic_y * width + pic_x]; - ref_data = &ref->y_data[ref_y * width + ref_x]; - result += sad(pic_data, ref_data, block_width, block_height, width); + if (left && top) { + pic_data = &pic->y_data[0]; + ref_data = &ref->y_data[0]; + result += corner_sad(pic_data, ref_data, -ref_x, -ref_y, width); + + pic_data = &pic->y_data[-ref_x]; + ref_data = &ref->y_data[0]; + result += vertical_sad(pic_data, ref_data, block_width + ref_x, -ref_y, width); + + pic_data = &pic->y_data[-ref_y * width]; + ref_data = &ref->y_data[0]; + result += horizontal_sad(pic_data, ref_data, -ref_x, block_height + ref_y, width); + + pic_data = &pic->y_data[(pic_y - ref_y) * width + pic_x - ref_x]; + ref_data = &ref->y_data[0]; + result += sad(pic_data, ref_data, block_width + ref_x, block_height + ref_y, width); + } else if (top) { + + } else if (top && right) { + + } else if (left) { + + } else if (right) { + + } else if (bottom && left) { + + } else if (bottom) { + + } else if (bottom && right) { + + } else { + pic_data = &pic->y_data[pic_y * width + pic_x]; + ref_data = &ref->y_data[ref_y * width + ref_x]; + result += sad(pic_data, ref_data, block_width, block_height, width); + } + + #if USE_CHROMA_IN_MV_SEARCH // Halve everything because chroma is half the resolution. From 1fcb452479e604c28db308326dedb0fc9e1558c2 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 18:30:29 +0300 Subject: [PATCH 07/19] Simplify reference buffer calculation. --- src/search.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/search.c b/src/search.c index ecdac9f4..017a6f69 100644 --- a/src/search.c +++ b/src/search.c @@ -99,6 +99,8 @@ unsigned get_block_sad(picture *pic, picture *ref, int block_width, int block_height) { uint8_t *pic_data, *ref_data; + int mv_x = ref_x - pic_x; + int mv_y = ref_y - pic_y; int width = pic->width; int height = pic->height; int left = ref_x < 0; @@ -108,25 +110,27 @@ unsigned get_block_sad(picture *pic, picture *ref, unsigned result = 0; + // Center both picture buffer and reference buffer to the picture block, so + // that further references are relative to the block rather than the + // top-left corner of the picture. + pic_data = &pic->y_data[pic_y * width + pic_x]; + ref_data = &ref->y_data[pic_y * width + pic_x]; + // 0 means invalid, for now. //if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; if (left && top) { - pic_data = &pic->y_data[0]; - ref_data = &ref->y_data[0]; - result += corner_sad(pic_data, ref_data, -ref_x, -ref_y, width); + result += corner_sad(pic_data, ref_data, + -ref_x, -ref_y, width); - pic_data = &pic->y_data[-ref_x]; - ref_data = &ref->y_data[0]; - result += vertical_sad(pic_data, ref_data, block_width + ref_x, -ref_y, width); + result += vertical_sad(&pic_data[-ref_x], ref_data, + block_width - -ref_x, -ref_y, width); - pic_data = &pic->y_data[-ref_y * width]; - ref_data = &ref->y_data[0]; - result += horizontal_sad(pic_data, ref_data, -ref_x, block_height + ref_y, width); + result += horizontal_sad(&pic_data[-ref_y * width], ref_data, + -ref_x, block_height - -ref_y, width); - pic_data = &pic->y_data[(pic_y - ref_y) * width + pic_x - ref_x]; - ref_data = &ref->y_data[0]; - result += sad(pic_data, ref_data, block_width + ref_x, block_height + ref_y, width); + result += sad(&pic_data[-ref_y * width + -ref_x], ref_data, + block_width - -ref_x, block_height - -ref_y, width); } else if (top) { } else if (top && right) { @@ -142,9 +146,7 @@ unsigned get_block_sad(picture *pic, picture *ref, } else if (bottom && right) { } else { - pic_data = &pic->y_data[pic_y * width + pic_x]; - ref_data = &ref->y_data[ref_y * width + ref_x]; - result += sad(pic_data, ref_data, block_width, block_height, width); + result += sad(pic_data, &ref_data[mv_y * width + mv_x], block_width, block_height, width); } From 0e078b2d18c5955cd4f304e823176595137d8872 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 18:42:30 +0300 Subject: [PATCH 08/19] Rethink SAD-calculation. --- src/search.c | 85 +++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/src/search.c b/src/search.c index 017a6f69..46c806e6 100644 --- a/src/search.c +++ b/src/search.c @@ -36,8 +36,8 @@ && (x) + (block_width) <= (width) \ && (y) + (block_height) <= (height)) -unsigned corner_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) +unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) { unsigned char ref = *ref_data; unsigned x, y; @@ -52,8 +52,8 @@ unsigned corner_sad(unsigned char* pic_data, unsigned char* ref_data, return sad; } -unsigned vertical_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) +unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) { unsigned x, y; unsigned sad = 0; @@ -67,8 +67,8 @@ unsigned vertical_sad(unsigned char* pic_data, unsigned char* ref_data, return sad; } -unsigned horizontal_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) +unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) { unsigned x, y; unsigned sad = 0; @@ -103,72 +103,55 @@ unsigned get_block_sad(picture *pic, picture *ref, int mv_y = ref_y - pic_y; int width = pic->width; int height = pic->height; - int left = ref_x < 0; - int right = ref_x + block_width > width; - int top = ref_y < 0; - int bottom = ref_y + block_height > height; + + // These are the number of pixels by how far the movement vector points + // outside the frame. They are always >= 0. If all of them are 0, the + // movement vector doesn't point outside the frame. + int left = (ref_x < 0) ? -ref_x : 0; + int top = (ref_y < 0) ? -ref_y : 0; + int right = (ref_x + block_width > width) ? ref_x - width : 0; + int bottom = (ref_y + block_height > height) ? ref_y - height : 0; unsigned result = 0; - // Center both picture buffer and reference buffer to the picture block, so - // that further references are relative to the block rather than the - // top-left corner of the picture. + // Center picture to the current block and reference to the point where + // movement vector is pointing to. That point might be outside the buffer, + // but that is ok because we project the movement vector to the buffer + // before dereferencing the pointer. pic_data = &pic->y_data[pic_y * width + pic_x]; - ref_data = &ref->y_data[pic_y * width + pic_x]; + ref_data = &ref->y_data[ref_y * width + ref_x]; // 0 means invalid, for now. //if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; + // The handling of movement vectors that point outside the picture is done + // in the following way. + // - Correct the index of ref_data so that it points to the top-left + // of the area we want to compare against. + // - Correct the index of pic_data to point inside the current block, so + // that we compare the right part of the block to the ref_data. + // - Reduce block_width and block_height so that the the size of the area + // being compared is correct. if (left && top) { - result += corner_sad(pic_data, ref_data, - -ref_x, -ref_y, width); - - result += vertical_sad(&pic_data[-ref_x], ref_data, - block_width - -ref_x, -ref_y, width); - - result += horizontal_sad(&pic_data[-ref_y * width], ref_data, - -ref_x, block_height - -ref_y, width); - - result += sad(&pic_data[-ref_y * width + -ref_x], ref_data, - block_width - -ref_x, block_height - -ref_y, width); - } else if (top) { } else if (top && right) { + } else if (top) { + + } else if (bottom && left) { + + } else if (bottom && right) { + } else if (left) { } else if (right) { - } else if (bottom && left) { - } else if (bottom) { - } else if (bottom && right) { - } else { - result += sad(pic_data, &ref_data[mv_y * width + mv_x], block_width, block_height, width); + result += sad(pic_data, ref_data, block_width, block_height, width); } - - - #if USE_CHROMA_IN_MV_SEARCH - // Halve everything because chroma is half the resolution. - width >>= 2; - pic_x >>= 2; - pic_y >>= 2; - ref_x >>= 2; - ref_y >>= 2; - block >>= 2; - - pic_data = &pic->u_data[pic_y * width + pic_x]; - ref_data = &ref->u_data[ref_y * width + ref_x]; - result += sad(pic_data, ref_data, block_width, block_height, width); - - pic_data = &pic->v_data[pic_y * width + pic_x]; - ref_data = &ref->v_data[ref_y * width + ref_x]; - result += sad(pic_data, ref_data, block_width, block_height, width); - #endif - return result; } From 4e369927521a6f77948c1a4f0d698ebcc1648aee Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 18:51:10 +0300 Subject: [PATCH 09/19] Move basic SAD functions to picture-module. --- src/picture.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++- src/picture.h | 11 +++++++++-- src/search.c | 52 +++------------------------------------------------ 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/src/picture.c b/src/picture.c index b8b5dccd..65e777f2 100644 --- a/src/picture.c +++ b/src/picture.c @@ -559,6 +559,52 @@ uint32_t sad4x4(int16_t *block1, uint32_t stride1, return sum; } +unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned char ref = *ref_data; + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref); + } + } + + return sad; +} + +unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref_data[x]); + } + } + + return sad; +} + +unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, + unsigned block_width, unsigned block_height, unsigned width) +{ + unsigned x, y; + unsigned sad = 0; + + for (y = 0; y < block_height; ++y) { + for (x = 0; x < block_width; ++x) { + sad += abs(pic_data[y * width + x] - ref_data[y * width]); + } + } + + return sad; +} + /** * \brief Calculate Sum of Absolute Differences (SAD) * @@ -573,7 +619,7 @@ uint32_t sad4x4(int16_t *block1, uint32_t stride1, * * \returns Sum of Absolute Differences */ -uint32_t sad(uint8_t *data1, uint8_t *data2, +uint32_t reg_sad(uint8_t *data1, uint8_t *data2, unsigned width, unsigned height, unsigned stride) { unsigned y, x; diff --git a/src/picture.h b/src/picture.h index 5ab5af81..bfc6c1d1 100644 --- a/src/picture.h +++ b/src/picture.h @@ -120,8 +120,15 @@ uint32_t sad8x8(int16_t *block1, uint32_t stride1, int16_t* block2, uint32_t stride2); uint32_t sad4x4(int16_t *block1, uint32_t stride1, int16_t* block2, uint32_t stride2); -uint32_t sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride); + +uint32_t cor_sad(uint8_t *data1, uint8_t *data2, + unsigned width, unsigned height, unsigned stride); +uint32_t ver_sad(uint8_t *data1, uint8_t *data2, + unsigned width, unsigned height, unsigned stride); +uint32_t hor_sad(uint8_t *data1, uint8_t *data2, + unsigned width, unsigned height, unsigned stride); +uint32_t reg_sad(uint8_t *data1, uint8_t *data2, + unsigned width, unsigned height, unsigned stride); double image_psnr(uint8_t *frame1, uint8_t *frame2, int32_t x, int32_t y); diff --git a/src/search.c b/src/search.c index 46c806e6..7d3e0fb4 100644 --- a/src/search.c +++ b/src/search.c @@ -36,52 +36,6 @@ && (x) + (block_width) <= (width) \ && (y) + (block_height) <= (height)) -unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) -{ - unsigned char ref = *ref_data; - unsigned x, y; - unsigned sad = 0; - - for (y = 0; y < block_height; ++y) { - for (x = 0; x < block_width; ++x) { - sad += abs(pic_data[y * width + x] - ref); - } - } - - return sad; -} - -unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) -{ - unsigned x, y; - unsigned sad = 0; - - for (y = 0; y < block_height; ++y) { - for (x = 0; x < block_width; ++x) { - sad += abs(pic_data[y * width + x] - ref_data[x]); - } - } - - return sad; -} - -unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) -{ - unsigned x, y; - unsigned sad = 0; - - for (y = 0; y < block_height; ++y) { - for (x = 0; x < block_width; ++x) { - sad += abs(pic_data[y * width + x] - ref_data[y * width]); - } - } - - return sad; -} - /** * \brief Get Sum of Absolute Differences (SAD) between two blocks in two * different frames. @@ -149,7 +103,7 @@ unsigned get_block_sad(picture *pic, picture *ref, } else if (bottom) { } else { - result += sad(pic_data, ref_data, block_width, block_height, width); + result += reg_sad(pic_data, ref_data, block_width, block_height, width); } return result; @@ -406,8 +360,8 @@ void search_mv_full(picture *pic, uint8_t *pic_data, uint8_t *ref_data, if (orig_x + x < 0 || orig_y + y < 0 || orig_x + x > pic->width - block_width || orig_y + y > pic->height - block_height) return; - cost = sad(pic_data, &ref_data[(orig_y + y) * pic->width + (orig_x + x)], - block_width, block_height, pic->width) + 1; + cost = reg_sad(pic_data, &ref_data[(orig_y + y) * pic->width + (orig_x + x)], + block_width, block_height, pic->width) + 1; if (cost < cur_cu->inter.cost) { cur_cu->inter.cost = cost; cur_cu->inter.mv[0] = x << 2; From d3561146d896dd1dd1867b50c2892a5e1bda0cc5 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 19:09:44 +0300 Subject: [PATCH 10/19] Change sad-tests to use chars instead of numbers to help with debugging. 1 + 48 is ascii '1' and so on. --- tests/sad_tests.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index 21240ec6..e01517a1 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -45,11 +45,16 @@ picture *g_ref = 0; // SETUP, TEARDOWN AND HELPER FUNCTIONS void sad_setup(void) { + unsigned i; g_pic = picture_init(8, 8, 1, 1); - memcpy(g_pic->y_data, pic_data, 64); + for (i = 0; i < 64; ++i) { + g_pic->y_data[i] = pic_data[i] + 48; + } g_ref = picture_init(8, 8, 1, 1); - memcpy(g_ref->y_data, ref_data, 64); + for (i = 0; i < 64; ++i) { + g_ref->y_data[i] = ref_data[i] + 48; + } } void sad_teardown(void) From 7e6c9aefe8a2f876fad159752289207e7ad628ac Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Thu, 10 Oct 2013 20:04:28 +0300 Subject: [PATCH 11/19] Add handling of more cases to sad calculation. --- src/search.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/search.c b/src/search.c index 7d3e0fb4..7f10cb88 100644 --- a/src/search.c +++ b/src/search.c @@ -63,8 +63,8 @@ unsigned get_block_sad(picture *pic, picture *ref, // movement vector doesn't point outside the frame. int left = (ref_x < 0) ? -ref_x : 0; int top = (ref_y < 0) ? -ref_y : 0; - int right = (ref_x + block_width > width) ? ref_x - width : 0; - int bottom = (ref_y + block_height > height) ? ref_y - height : 0; + int right = (ref_x + block_width > width) ? ref_x + block_width - width : 0; + int bottom = (ref_y + block_height > height) ? ref_y + block_height - height : 0; unsigned result = 0; @@ -87,11 +87,30 @@ unsigned get_block_sad(picture *pic, picture *ref, // - Reduce block_width and block_height so that the the size of the area // being compared is correct. if (left && top) { - + result += cor_sad(pic_data, &ref_data[top * width + left], + left, top, width); + result += ver_sad(&pic_data[left], &ref_data[top * width + left], + block_width - left, top, width); + result += hor_sad(&pic_data[top * width], &ref_data[top * width + left], + left, block_height - top, width); + result += reg_sad(&pic_data[top * width + left], &ref_data[top * width + left], + block_width - left, block_height - top, width); } else if (top && right) { - + result += ver_sad(pic_data, &ref_data[top * width], + block_width - right, top, width); + result += cor_sad(&pic_data[block_width - right], + &ref_data[top * width + (block_width - right - 1)], + right, top, width); + result += reg_sad(&pic_data[top * width], &ref_data[top * width], + block_width - right, block_height - top, width); + result += hor_sad(&pic_data[top * width + (block_width - right)], + &ref_data[top * width + (block_width - right - 1)], + right, block_height - top, width); } else if (top) { - + result += ver_sad(pic_data, &ref_data[top * width], + block_width, top, width); + result += reg_sad(&pic_data[top * width], &ref_data[top * width], + block_width, block_height - top, width); } else if (bottom && left) { } else if (bottom && right) { From b58a6387ee477b1fd236fd162708c3849b5423e7 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 11:04:49 +0300 Subject: [PATCH 12/19] Clean up the code a bit. --- src/search.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/search.c b/src/search.c index 7f10cb88..fcc86f32 100644 --- a/src/search.c +++ b/src/search.c @@ -87,29 +87,37 @@ unsigned get_block_sad(picture *pic, picture *ref, // - Reduce block_width and block_height so that the the size of the area // being compared is correct. if (left && top) { - result += cor_sad(pic_data, &ref_data[top * width + left], + result += cor_sad(pic_data, + &ref_data[top * width + left], left, top, width); - result += ver_sad(&pic_data[left], &ref_data[top * width + left], + result += ver_sad(&pic_data[left], + &ref_data[top * width + left], block_width - left, top, width); - result += hor_sad(&pic_data[top * width], &ref_data[top * width + left], + result += hor_sad(&pic_data[top * width], + &ref_data[top * width + left], left, block_height - top, width); - result += reg_sad(&pic_data[top * width + left], &ref_data[top * width + left], + result += reg_sad(&pic_data[top * width + left], + &ref_data[top * width + left], block_width - left, block_height - top, width); } else if (top && right) { - result += ver_sad(pic_data, &ref_data[top * width], + result += ver_sad(pic_data, + &ref_data[top * width], block_width - right, top, width); result += cor_sad(&pic_data[block_width - right], &ref_data[top * width + (block_width - right - 1)], right, top, width); - result += reg_sad(&pic_data[top * width], &ref_data[top * width], + result += reg_sad(&pic_data[top * width], + &ref_data[top * width], block_width - right, block_height - top, width); result += hor_sad(&pic_data[top * width + (block_width - right)], &ref_data[top * width + (block_width - right - 1)], right, block_height - top, width); } else if (top) { - result += ver_sad(pic_data, &ref_data[top * width], + result += ver_sad(pic_data, + &ref_data[top * width], block_width, top, width); - result += reg_sad(&pic_data[top * width], &ref_data[top * width], + result += reg_sad(&pic_data[top * width], + &ref_data[top * width], block_width, block_height - top, width); } else if (bottom && left) { From 22262dbc98270d6d471803c412d8c5ebfd9bb638 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 12:38:14 +0300 Subject: [PATCH 13/19] Fix a bug in a test. --- tests/sad_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index e01517a1..1452708b 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -125,7 +125,7 @@ void test_bottomright(void) { assert_ulong_equal( 9*(4*4) + (6+8)*(4*4) + 5*(4*4) - 64, - TEST_SAD(-3, 3)); + TEST_SAD(3, 3)); } ////////////////////////////////////////////////////////////////////////// From 235b1ec0bc1dd1b4d315a148018a6e27d62fd185 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 12:39:56 +0300 Subject: [PATCH 14/19] Add rest of the quadrants for sad calculation. - All tests pass. - Movement vectors that don't overlap with the frame aren't handled yet. --- src/search.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/search.c b/src/search.c index fcc86f32..5ca0a877 100644 --- a/src/search.c +++ b/src/search.c @@ -120,15 +120,52 @@ unsigned get_block_sad(picture *pic, picture *ref, &ref_data[top * width], block_width, block_height - top, width); } else if (bottom && left) { - + result += hor_sad(pic_data, + &ref_data[left], + left, block_height - bottom, width); + result += reg_sad(&pic_data[left], + &ref_data[left], + block_width - left, block_height - bottom, width); + result += cor_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width + left], + left, bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width + left], + &ref_data[(block_height - bottom - 1) * width + left], + block_width - left, bottom, width); } else if (bottom && right) { - + result += reg_sad(pic_data, + ref_data, + block_width - right, block_height - bottom, width); + result += hor_sad(&pic_data[block_width - right], + &ref_data[block_width - right - 1], + right, block_height - bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width], + block_width - right, bottom, width); + result += cor_sad(&pic_data[(block_height - bottom) * width + block_width - right], + &ref_data[(block_height - bottom - 1) * width + block_width - right - 1], + right, bottom, width); } else if (left) { - + result += hor_sad(pic_data, + &ref_data[left], + left, block_height, width); + result += reg_sad(&pic_data[left], + &ref_data[left], + block_width - left, block_height, width); } else if (right) { - + result += reg_sad(pic_data, + ref_data, + block_width - right, block_height, width); + result += hor_sad(&pic_data[block_width - right], + &ref_data[block_width - right - 1], + right, block_height, width); } else if (bottom) { - + result += reg_sad(pic_data, + ref_data, + block_width, block_height - bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width], + block_width, bottom, width); } else { result += reg_sad(pic_data, ref_data, block_width, block_height, width); } From 0df974cb0d60e1d0ad9d76871ac7818fd19d8e63 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 12:51:53 +0300 Subject: [PATCH 15/19] Change sad functions to accept negative block widths. This makes boundary checking clearer. --- src/picture.c | 18 +++++++++--------- src/picture.h | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/picture.c b/src/picture.c index 65e777f2..03b03478 100644 --- a/src/picture.c +++ b/src/picture.c @@ -560,10 +560,10 @@ uint32_t sad4x4(int16_t *block1, uint32_t stride1, } unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) + int block_width, int block_height, unsigned width) { unsigned char ref = *ref_data; - unsigned x, y; + int x, y; unsigned sad = 0; for (y = 0; y < block_height; ++y) { @@ -576,9 +576,9 @@ unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, } unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) + int block_width, int block_height, unsigned width) { - unsigned x, y; + int x, y; unsigned sad = 0; for (y = 0; y < block_height; ++y) { @@ -591,9 +591,9 @@ unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, } unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, - unsigned block_width, unsigned block_height, unsigned width) + int block_width, int block_height, unsigned width) { - unsigned x, y; + int x, y; unsigned sad = 0; for (y = 0; y < block_height; ++y) { @@ -619,10 +619,10 @@ unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, * * \returns Sum of Absolute Differences */ -uint32_t reg_sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride) +unsigned reg_sad(uint8_t *data1, uint8_t *data2, + int width, int height, unsigned stride) { - unsigned y, x; + int y, x; unsigned sad = 0; for (y = 0; y < height; ++y) { diff --git a/src/picture.h b/src/picture.h index bfc6c1d1..aa9e52f2 100644 --- a/src/picture.h +++ b/src/picture.h @@ -121,14 +121,14 @@ uint32_t sad8x8(int16_t *block1, uint32_t stride1, uint32_t sad4x4(int16_t *block1, uint32_t stride1, int16_t* block2, uint32_t stride2); -uint32_t cor_sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride); -uint32_t ver_sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride); -uint32_t hor_sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride); -uint32_t reg_sad(uint8_t *data1, uint8_t *data2, - unsigned width, unsigned height, unsigned stride); +unsigned cor_sad(uint8_t *data1, uint8_t *data2, + int width, int height, unsigned stride); +unsigned ver_sad(uint8_t *data1, uint8_t *data2, + int width, int height, unsigned stride); +unsigned hor_sad(uint8_t *data1, uint8_t *data2, + int width, int height, unsigned stride); +unsigned reg_sad(uint8_t *data1, uint8_t *data2, + int width, int height, unsigned stride); double image_psnr(uint8_t *frame1, uint8_t *frame2, int32_t x, int32_t y); From b155d825bed3110eda9d70e376d114796e6c9edb Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 14:08:56 +0300 Subject: [PATCH 16/19] Add tests for movement vectors that are completely out of frame. --- tests/sad_tests.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index 1452708b..b7e99f1f 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -64,7 +64,7 @@ void sad_teardown(void) } ////////////////////////////////////////////////////////////////////////// -// TESTS +// OVERLAPPING BOUNDARY TESTS void test_topleft(void) { assert_ulong_equal( @@ -128,6 +128,65 @@ void test_bottomright(void) TEST_SAD(3, 3)); } +////////////////////////////////////////////////////////////////////////// +// OUT OF FRAME TESTS + +void test_topleft_out(void) +{ + assert_ulong_equal( + 1*(8*8) - 64, + TEST_SAD(-8, -8)); +} + +void test_top_out(void) +{ + assert_ulong_equal( + (1+3)*8 + 2*(6*8) - 64, + TEST_SAD(0, -8)); +} + +void test_topright_out(void) +{ + assert_ulong_equal( + 3*(8*8) - 64, + TEST_SAD(8, -8)); +} + +void test_left_out(void) +{ + assert_ulong_equal( + (1+7)*8 + 4*(6*8) - 64, + TEST_SAD(-8, 0)); +} + +void test_right_out(void) +{ + assert_ulong_equal( + (3+9)*8 + 6*(6*8) - 64, + TEST_SAD(8, 0)); +} + +void test_bottomleft_out(void) +{ + assert_ulong_equal( + 7*(8*8) - 64, + TEST_SAD(-8, 8)); +} + +void test_bottom_out(void) +{ + assert_ulong_equal( + (7+9)*8 + 8*(6*8) - 64, + TEST_SAD(0, 8)); +} + +void test_bottomright_out(void) +{ + assert_ulong_equal( + 9*(8*8) - 64, + TEST_SAD(8, 8)); +} + ////////////////////////////////////////////////////////////////////////// // TEST FIXTURES void sad_tests(void) @@ -135,6 +194,8 @@ void sad_tests(void) test_fixture_start(); fixture_setup(sad_setup); + + // Tests for movement vectors that overlap frame. run_test(test_topleft); run_test(test_top); run_test(test_topright); @@ -147,6 +208,19 @@ void sad_tests(void) run_test(test_bottom); run_test(test_bottomright); + // Tests for movement vectors that are outside the frame. + run_test(test_topleft_out); + run_test(test_top_out); + run_test(test_topright_out); + + run_test(test_left_out); + run_test(test_right_out); + + run_test(test_bottomleft_out); + run_test(test_bottom_out); + run_test(test_bottomright_out); + + fixture_teardown(sad_teardown); test_fixture_end(); } From be501f720cc964731e733e4445cc592ae6d6222b Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 14:09:28 +0300 Subject: [PATCH 17/19] Reorder conditions. --- src/search.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/search.c b/src/search.c index 5ca0a877..b0a6e741 100644 --- a/src/search.c +++ b/src/search.c @@ -86,7 +86,7 @@ unsigned get_block_sad(picture *pic, picture *ref, // that we compare the right part of the block to the ref_data. // - Reduce block_width and block_height so that the the size of the area // being compared is correct. - if (left && top) { + if (top && left) { result += cor_sad(pic_data, &ref_data[top * width + left], left, top, width); @@ -112,13 +112,6 @@ unsigned get_block_sad(picture *pic, picture *ref, result += hor_sad(&pic_data[top * width + (block_width - right)], &ref_data[top * width + (block_width - right - 1)], right, block_height - top, width); - } else if (top) { - result += ver_sad(pic_data, - &ref_data[top * width], - block_width, top, width); - result += reg_sad(&pic_data[top * width], - &ref_data[top * width], - block_width, block_height - top, width); } else if (bottom && left) { result += hor_sad(pic_data, &ref_data[left], @@ -145,6 +138,20 @@ unsigned get_block_sad(picture *pic, picture *ref, result += cor_sad(&pic_data[(block_height - bottom) * width + block_width - right], &ref_data[(block_height - bottom - 1) * width + block_width - right - 1], right, bottom, width); + } else if (top) { + result += ver_sad(pic_data, + &ref_data[top * width], + block_width, top, width); + result += reg_sad(&pic_data[top * width], + &ref_data[top * width], + block_width, block_height - top, width); + } else if (bottom) { + result += reg_sad(pic_data, + ref_data, + block_width, block_height - bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width], + block_width, bottom, width); } else if (left) { result += hor_sad(pic_data, &ref_data[left], @@ -159,13 +166,6 @@ unsigned get_block_sad(picture *pic, picture *ref, result += hor_sad(&pic_data[block_width - right], &ref_data[block_width - right - 1], right, block_height, width); - } else if (bottom) { - result += reg_sad(pic_data, - ref_data, - block_width, block_height - bottom, width); - result += ver_sad(&pic_data[(block_height - bottom) * width], - &ref_data[(block_height - bottom - 1) * width], - block_width, bottom, width); } else { result += reg_sad(pic_data, ref_data, block_width, block_height, width); } From 69d1f6d1e2106c48d7851534b1ba2e15e3a63150 Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 15:19:21 +0300 Subject: [PATCH 18/19] Clean up the code. - Rename get_block_sad to calc_sad and handle special cases in general_sad. - Remove old search functions because I don't want to update or test them. --- src/search.c | 216 ++++++++------------------------------------ tests/sad_tests.cpp | 8 +- 2 files changed, 42 insertions(+), 182 deletions(-) diff --git a/src/search.c b/src/search.c index b0a6e741..59e35b98 100644 --- a/src/search.c +++ b/src/search.c @@ -28,7 +28,6 @@ #define USE_INTRA_IN_P 0 //#define RENDER_CU encoder->frame==2 #define RENDER_CU 0 -#define USE_FULL_SEARCH 0 #define USE_CHROMA_IN_MV_SEARCH 0 #define IN_FRAME(x, y, width, height, block_width, block_height) \ @@ -48,13 +47,11 @@ * \param block_width Width of the blocks. * \param block_height Height of the blocks. */ -unsigned get_block_sad(picture *pic, picture *ref, - int pic_x, int pic_y, int ref_x, int ref_y, - int block_width, int block_height) +unsigned general_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height) { uint8_t *pic_data, *ref_data; - int mv_x = ref_x - pic_x; - int mv_y = ref_y - pic_y; int width = pic->width; int height = pic->height; @@ -75,9 +72,6 @@ unsigned get_block_sad(picture *pic, picture *ref, pic_data = &pic->y_data[pic_y * width + pic_x]; ref_data = &ref->y_data[ref_y * width + ref_x]; - // 0 means invalid, for now. - //if (!IN_FRAME(ref_x, ref_y, width, height, block_width, block_height)) return 0; - // The handling of movement vectors that point outside the picture is done // in the following way. // - Correct the index of ref_data so that it points to the top-left @@ -173,6 +167,23 @@ unsigned get_block_sad(picture *pic, picture *ref, return result; } + +unsigned calc_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height) +{ + if (ref_x >= 0 && ref_x <= pic->width - block_width && + ref_y >= 0 && ref_y <= pic->height - block_height) + { + uint8_t *pic_data = &pic->y_data[pic_y * pic->width + pic_x]; + uint8_t *ref_data = &ref->y_data[ref_y * pic->width + ref_x]; + reg_sad(pic_data, ref_data, block_width, block_height, pic->width); + } else { + return general_sad(pic, ref, pic_x, pic_y, ref_x, ref_y, block_width, block_height); + } +} + + typedef struct { int x; int y; @@ -217,9 +228,9 @@ void hexagon_search(picture *pic, picture *ref, // Search the initial 7 points of the hexagon. for (i = 0; i < 7; ++i) { const vector2d *pattern = large_hexbs + i; - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x + pattern->x, orig_y + y + pattern->y, - block_width, block_width); + unsigned cost = calc_sad(pic, ref, orig_x, orig_y, + orig_x + x + pattern->x, orig_y + y + pattern->y, + block_width, block_width); if (cost > 0 && cost < best_cost) { best_cost = cost; best_index = i; @@ -228,9 +239,9 @@ void hexagon_search(picture *pic, picture *ref, // Try the 0,0 vector. if (!(x == 0 && y == 0)) { - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x, orig_y, - block_width, block_width); + unsigned cost = calc_sad(pic, ref, orig_x, orig_y, + orig_x, orig_y, + block_width, block_width); if (cost > 0 && cost < best_cost) { best_cost = cost; best_index = 0; @@ -240,9 +251,9 @@ void hexagon_search(picture *pic, picture *ref, // Redo the search around the 0,0 point. for (i = 1; i < 7; ++i) { const vector2d *pattern = large_hexbs + i; - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + pattern->x, orig_y + pattern->y, - block_width, block_width); + unsigned cost = calc_sad(pic, ref, orig_x, orig_y, + orig_x + pattern->x, orig_y + pattern->y, + block_width, block_width); if (cost > 0 && cost < best_cost) { best_cost = cost; best_index = i; @@ -271,9 +282,9 @@ void hexagon_search(picture *pic, picture *ref, // Iterate through the next 3 points. for (i = 0; i < 3; ++i) { const vector2d *offset = large_hexbs + start + i; - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x + offset->x, orig_y + y + offset->y, - block_width, block_width); + unsigned cost = calc_sad(pic, ref, orig_x, orig_y, + orig_x + x + offset->x, orig_y + y + offset->y, + block_width, block_width); if (cost > 0 && cost < best_cost) { best_cost = cost; best_index = start + i; @@ -288,9 +299,9 @@ void hexagon_search(picture *pic, picture *ref, best_index = 0; for (i = 1; i < 5; ++i) { const vector2d *offset = small_hexbs + i; - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x + offset->x, orig_y + y + offset->y, - block_width, block_width); + unsigned cost = calc_sad(pic, ref, orig_x, orig_y, + orig_x + x + offset->x, orig_y + y + offset->y, + block_width, block_width); if (cost > 0 && cost < best_cost) { best_cost = cost; best_index = i; @@ -305,146 +316,6 @@ void hexagon_search(picture *pic, picture *ref, cur_cu->inter.mv[1] = y << 2; } -void search_mv(picture *pic, picture *ref, - cu_info *cur_cu, int orig_x, int orig_y, int x, int y, - unsigned depth) -{ - int block_width = CU_WIDTH_FROM_DEPTH(depth); - - // Get cost for the predicted motion vector. - unsigned cost = get_block_sad(pic, ref, orig_x, orig_y, orig_x + x, orig_y + y, - block_width, block_width); - unsigned best_cost = -1; - unsigned step = 8; - - if (cost > 0) { - best_cost = cost; - cur_cu->inter.mv[0] = x; - cur_cu->inter.mv[1] = y; - } - - // If initial vector is long, also try the (0, 0) vector just in case. - if (x != 0 || y != 0) { - cost = get_block_sad(pic, ref, orig_x, orig_y, orig_x, orig_y, - block_width, block_width); - - if (cost > 0 && cost < best_cost) { - best_cost = cost; - cur_cu->inter.mv[0] = 0; - cur_cu->inter.mv[1] = 0; - } - } - - while (step > 0) { - // Stop if current best vector is already really good. - // This is an experimental condition. - // The constant 1.8 is there because there is some SAD cost when comparing - // against the reference even if the frame doesn't change. This is probably - // due to quantization. It's value is just a guess based on the first - // blocks of the BQMall sequence, which don't move. - // TODO: Quantization factor probably affects what the constant should be. - /* - if (best_cost <= block_width * block_width * 1.8) { - break; - } - */ - - // Change center of search to the current best point. - x = cur_cu->inter.mv[0]; - y = cur_cu->inter.mv[1]; - - // above - cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x, orig_y + y - step, - block_width, block_width); - if (cost > 0 && cost < best_cost) { - best_cost = cost; - cur_cu->inter.mv[0] = x; - cur_cu->inter.mv[1] = y - step; - } - - // left - cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x - step, orig_y + y, - block_width, block_width); - if (cost > 0 && cost < best_cost) { - best_cost = cost; - cur_cu->inter.mv[0] = x - step; - cur_cu->inter.mv[1] = y; - } - - // right - cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x + step, orig_y + y, - block_width, block_width); - if (cost > 0 && cost < best_cost) { - best_cost = cost; - cur_cu->inter.mv[0] = x + step; - cur_cu->inter.mv[1] = y; - } - - // below - cost = get_block_sad(pic, ref, orig_x, orig_y, - orig_x + x, orig_y + y + step, - block_width, block_width); - if (cost > 0 && cost < best_cost) { - best_cost = cost; - cur_cu->inter.mv[0] = x; - cur_cu->inter.mv[1] = y + step; - } - - // Reduce search area by half. - step /= 2; - } - - cur_cu->inter.cost = best_cost + 1; // +1 so that cost is > 0. - cur_cu->inter.mv[0] <<= 2; - cur_cu->inter.mv[1] <<= 2; -} - -/** - * \brief Search motions vectors for a block and all it's sub-blocks. - * - * \param pic - * \param pic_data picture color data starting from the block MV is being searched for. - * \param ref_data picture color data starting from the beginning of reference pic. - * \param cur_cu - */ -void search_mv_full(picture *pic, uint8_t *pic_data, uint8_t *ref_data, - cu_info *cur_cu, unsigned step, - int orig_x, int orig_y, int x, int y, unsigned depth) -{ - // TODO: Inter: Handle non-square blocks. - int block_width = CU_WIDTH_FROM_DEPTH(depth); - int block_height = block_width; - unsigned cost; - - // TODO: Inter: Calculating error outside picture borders. - // This prevents choosing vectors that need interpolating of borders to work. - if (orig_x + x < 0 || orig_y + y < 0 || orig_x + x > pic->width - block_width - || orig_y + y > pic->height - block_height) return; - - cost = reg_sad(pic_data, &ref_data[(orig_y + y) * pic->width + (orig_x + x)], - block_width, block_height, pic->width) + 1; - if (cost < cur_cu->inter.cost) { - cur_cu->inter.cost = cost; - cur_cu->inter.mv[0] = x << 2; - cur_cu->inter.mv[1] = y << 2; - } - - step /= 2; - if (step > 0) { - search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y, - x, y - step, depth); - search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y, - x - step, y, depth); - search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y, - x + step, y, depth); - search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y, - x, y + step, depth); - } -} - /** * \brief */ @@ -586,20 +457,9 @@ void search_tree(encoder_control *encoder, start_y = ref_cu->inter.mv[1] >> 2; } - if (USE_FULL_SEARCH) { - search_mv_full(cur_pic, cur_data, ref_pic->y_data, - cur_cu, 8, x, y, - start_x, start_y, depth); - } else { - /* - search_mv(cur_pic, ref_pic, - cur_cu, x, y, - start_x, start_y, depth); - */ - hexagon_search(cur_pic, ref_pic, - cur_cu, x, y, - start_x, start_y, depth); - } + hexagon_search(cur_pic, ref_pic, + cur_cu, x, y, + start_x, start_y, depth); } cur_cu->type = CU_INTER; diff --git a/tests/sad_tests.cpp b/tests/sad_tests.cpp index b7e99f1f..aa4aa168 100644 --- a/tests/sad_tests.cpp +++ b/tests/sad_tests.cpp @@ -6,13 +6,13 @@ ////////////////////////////////////////////////////////////////////////// // EXTERNAL FUNCTIONS -unsigned get_block_sad(picture *pic, picture *ref, - int pic_x, int pic_y, int ref_x, int ref_y, - int block_width, int block_height); +unsigned calc_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height); ////////////////////////////////////////////////////////////////////////// // DEFINES -#define TEST_SAD(X, Y) get_block_sad(g_pic, g_ref, 0, 0, (X), (Y), 8, 8) +#define TEST_SAD(X, Y) calc_sad(g_pic, g_ref, 0, 0, (X), (Y), 8, 8) ////////////////////////////////////////////////////////////////////////// // GLOBALS From 0c3bd7e22318573a12406d18753d670adb6a125e Mon Sep 17 00:00:00 2001 From: Ari Koivula Date: Fri, 11 Oct 2013 15:31:55 +0300 Subject: [PATCH 19/19] Move SAD calculations to picture module. --- src/picture.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/picture.h | 11 +-- src/search.c | 149 -------------------------------------- 3 files changed, 200 insertions(+), 157 deletions(-) diff --git a/src/picture.c b/src/picture.c index 03b03478..cbe62cfb 100644 --- a/src/picture.c +++ b/src/picture.c @@ -559,6 +559,17 @@ uint32_t sad4x4(int16_t *block1, uint32_t stride1, return sum; } +/** + * \brief Diagonally interpolate SAD outside the frame. + * + * \param data1 Starting point of the first picture. + * \param data2 Starting point of the second picture. + * \param width Width of the region for which SAD is calculated. + * \param height Height of the region for which SAD is calculated. + * \param width Width of the pixel array. + * + * \returns Sum of Absolute Differences + */ unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, int block_width, int block_height, unsigned width) { @@ -575,6 +586,17 @@ unsigned cor_sad(unsigned char* pic_data, unsigned char* ref_data, return sad; } +/** + * \brief Vertically interpolate SAD outside the frame. + * + * \param data1 Starting point of the first picture. + * \param data2 Starting point of the second picture. + * \param width Width of the region for which SAD is calculated. + * \param height Height of the region for which SAD is calculated. + * \param width Width of the pixel array. + * + * \returns Sum of Absolute Differences + */ unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, int block_width, int block_height, unsigned width) { @@ -590,6 +612,17 @@ unsigned ver_sad(unsigned char* pic_data, unsigned char* ref_data, return sad; } +/** + * \brief Horizontally interpolate SAD outside the frame. + * + * \param data1 Starting point of the first picture. + * \param data2 Starting point of the second picture. + * \param width Width of the region for which SAD is calculated. + * \param height Height of the region for which SAD is calculated. + * \param width Width of the pixel array. + * + * \returns Sum of Absolute Differences + */ unsigned hor_sad(unsigned char* pic_data, unsigned char* ref_data, int block_width, int block_height, unsigned width) { @@ -633,3 +666,167 @@ unsigned reg_sad(uint8_t *data1, uint8_t *data2, return sad; } + +/** + * \brief Handle special cases of comparing blocks that are not completely + * inside the frame. + * + * \param pic First frame. + * \param ref Second frame. + * \param pic_x X coordinate of the first block. + * \param pic_y Y coordinate of the first block. + * \param ref_x X coordinate of the second block. + * \param ref_y Y coordinate of the second block. + * \param block_width Width of the blocks. + * \param block_height Height of the blocks. + */ +unsigned interpolated_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height) +{ + uint8_t *pic_data, *ref_data; + int width = pic->width; + int height = pic->height; + + // These are the number of pixels by how far the movement vector points + // outside the frame. They are always >= 0. If all of them are 0, the + // movement vector doesn't point outside the frame. + int left = (ref_x < 0) ? -ref_x : 0; + int top = (ref_y < 0) ? -ref_y : 0; + int right = (ref_x + block_width > width) ? ref_x + block_width - width : 0; + int bottom = (ref_y + block_height > height) ? ref_y + block_height - height : 0; + + unsigned result = 0; + + // Center picture to the current block and reference to the point where + // movement vector is pointing to. That point might be outside the buffer, + // but that is ok because we project the movement vector to the buffer + // before dereferencing the pointer. + pic_data = &pic->y_data[pic_y * width + pic_x]; + ref_data = &ref->y_data[ref_y * width + ref_x]; + + // The handling of movement vectors that point outside the picture is done + // in the following way. + // - Correct the index of ref_data so that it points to the top-left + // of the area we want to compare against. + // - Correct the index of pic_data to point inside the current block, so + // that we compare the right part of the block to the ref_data. + // - Reduce block_width and block_height so that the the size of the area + // being compared is correct. + if (top && left) { + result += cor_sad(pic_data, + &ref_data[top * width + left], + left, top, width); + result += ver_sad(&pic_data[left], + &ref_data[top * width + left], + block_width - left, top, width); + result += hor_sad(&pic_data[top * width], + &ref_data[top * width + left], + left, block_height - top, width); + result += reg_sad(&pic_data[top * width + left], + &ref_data[top * width + left], + block_width - left, block_height - top, width); + } else if (top && right) { + result += ver_sad(pic_data, + &ref_data[top * width], + block_width - right, top, width); + result += cor_sad(&pic_data[block_width - right], + &ref_data[top * width + (block_width - right - 1)], + right, top, width); + result += reg_sad(&pic_data[top * width], + &ref_data[top * width], + block_width - right, block_height - top, width); + result += hor_sad(&pic_data[top * width + (block_width - right)], + &ref_data[top * width + (block_width - right - 1)], + right, block_height - top, width); + } else if (bottom && left) { + result += hor_sad(pic_data, + &ref_data[left], + left, block_height - bottom, width); + result += reg_sad(&pic_data[left], + &ref_data[left], + block_width - left, block_height - bottom, width); + result += cor_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width + left], + left, bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width + left], + &ref_data[(block_height - bottom - 1) * width + left], + block_width - left, bottom, width); + } else if (bottom && right) { + result += reg_sad(pic_data, + ref_data, + block_width - right, block_height - bottom, width); + result += hor_sad(&pic_data[block_width - right], + &ref_data[block_width - right - 1], + right, block_height - bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width], + block_width - right, bottom, width); + result += cor_sad(&pic_data[(block_height - bottom) * width + block_width - right], + &ref_data[(block_height - bottom - 1) * width + block_width - right - 1], + right, bottom, width); + } else if (top) { + result += ver_sad(pic_data, + &ref_data[top * width], + block_width, top, width); + result += reg_sad(&pic_data[top * width], + &ref_data[top * width], + block_width, block_height - top, width); + } else if (bottom) { + result += reg_sad(pic_data, + ref_data, + block_width, block_height - bottom, width); + result += ver_sad(&pic_data[(block_height - bottom) * width], + &ref_data[(block_height - bottom - 1) * width], + block_width, bottom, width); + } else if (left) { + result += hor_sad(pic_data, + &ref_data[left], + left, block_height, width); + result += reg_sad(&pic_data[left], + &ref_data[left], + block_width - left, block_height, width); + } else if (right) { + result += reg_sad(pic_data, + ref_data, + block_width - right, block_height, width); + result += hor_sad(&pic_data[block_width - right], + &ref_data[block_width - right - 1], + right, block_height, width); + } else { + result += reg_sad(pic_data, ref_data, block_width, block_height, width); + } + + return result; +} + +/** + * \brief Get Sum of Absolute Differences (SAD) between two blocks in two + * different frames. + * + * \param pic First frame. + * \param ref Second frame. + * \param pic_x X coordinate of the first block. + * \param pic_y Y coordinate of the first block. + * \param ref_x X coordinate of the second block. + * \param ref_y Y coordinate of the second block. + * \param block_width Width of the blocks. + * \param block_height Height of the blocks. + */ +unsigned calc_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height) +{ + if (ref_x >= 0 && ref_x <= pic->width - block_width && + ref_y >= 0 && ref_y <= pic->height - block_height) + { + // Reference block is completely inside the frame, so just calculate the + // SAD directly. This is the most common case, which is why it's first. + uint8_t *pic_data = &pic->y_data[pic_y * pic->width + pic_x]; + uint8_t *ref_data = &ref->y_data[ref_y * pic->width + ref_x]; + return reg_sad(pic_data, ref_data, block_width, block_height, pic->width); + } else { + // Call a routine that knows how to interpolate pixels outside the frame. + return interpolated_sad(pic, ref, pic_x, pic_y, ref_x, ref_y, block_width, block_height); + } +} diff --git a/src/picture.h b/src/picture.h index aa9e52f2..3dfad348 100644 --- a/src/picture.h +++ b/src/picture.h @@ -121,14 +121,9 @@ uint32_t sad8x8(int16_t *block1, uint32_t stride1, uint32_t sad4x4(int16_t *block1, uint32_t stride1, int16_t* block2, uint32_t stride2); -unsigned cor_sad(uint8_t *data1, uint8_t *data2, - int width, int height, unsigned stride); -unsigned ver_sad(uint8_t *data1, uint8_t *data2, - int width, int height, unsigned stride); -unsigned hor_sad(uint8_t *data1, uint8_t *data2, - int width, int height, unsigned stride); -unsigned reg_sad(uint8_t *data1, uint8_t *data2, - int width, int height, unsigned stride); +unsigned calc_sad(picture *pic, picture *ref, + int pic_x, int pic_y, int ref_x, int ref_y, + int block_width, int block_height); double image_psnr(uint8_t *frame1, uint8_t *frame2, int32_t x, int32_t y); diff --git a/src/search.c b/src/search.c index 59e35b98..90f0744a 100644 --- a/src/search.c +++ b/src/search.c @@ -35,155 +35,6 @@ && (x) + (block_width) <= (width) \ && (y) + (block_height) <= (height)) -/** - * \brief Get Sum of Absolute Differences (SAD) between two blocks in two - * different frames. - * \param pic First frame. - * \param ref Second frame. - * \param pic_x X coordinate of the first block. - * \param pic_y Y coordinate of the first block. - * \param ref_x X coordinate of the second block. - * \param ref_y Y coordinate of the second block. - * \param block_width Width of the blocks. - * \param block_height Height of the blocks. - */ -unsigned general_sad(picture *pic, picture *ref, - int pic_x, int pic_y, int ref_x, int ref_y, - int block_width, int block_height) -{ - uint8_t *pic_data, *ref_data; - int width = pic->width; - int height = pic->height; - - // These are the number of pixels by how far the movement vector points - // outside the frame. They are always >= 0. If all of them are 0, the - // movement vector doesn't point outside the frame. - int left = (ref_x < 0) ? -ref_x : 0; - int top = (ref_y < 0) ? -ref_y : 0; - int right = (ref_x + block_width > width) ? ref_x + block_width - width : 0; - int bottom = (ref_y + block_height > height) ? ref_y + block_height - height : 0; - - unsigned result = 0; - - // Center picture to the current block and reference to the point where - // movement vector is pointing to. That point might be outside the buffer, - // but that is ok because we project the movement vector to the buffer - // before dereferencing the pointer. - pic_data = &pic->y_data[pic_y * width + pic_x]; - ref_data = &ref->y_data[ref_y * width + ref_x]; - - // The handling of movement vectors that point outside the picture is done - // in the following way. - // - Correct the index of ref_data so that it points to the top-left - // of the area we want to compare against. - // - Correct the index of pic_data to point inside the current block, so - // that we compare the right part of the block to the ref_data. - // - Reduce block_width and block_height so that the the size of the area - // being compared is correct. - if (top && left) { - result += cor_sad(pic_data, - &ref_data[top * width + left], - left, top, width); - result += ver_sad(&pic_data[left], - &ref_data[top * width + left], - block_width - left, top, width); - result += hor_sad(&pic_data[top * width], - &ref_data[top * width + left], - left, block_height - top, width); - result += reg_sad(&pic_data[top * width + left], - &ref_data[top * width + left], - block_width - left, block_height - top, width); - } else if (top && right) { - result += ver_sad(pic_data, - &ref_data[top * width], - block_width - right, top, width); - result += cor_sad(&pic_data[block_width - right], - &ref_data[top * width + (block_width - right - 1)], - right, top, width); - result += reg_sad(&pic_data[top * width], - &ref_data[top * width], - block_width - right, block_height - top, width); - result += hor_sad(&pic_data[top * width + (block_width - right)], - &ref_data[top * width + (block_width - right - 1)], - right, block_height - top, width); - } else if (bottom && left) { - result += hor_sad(pic_data, - &ref_data[left], - left, block_height - bottom, width); - result += reg_sad(&pic_data[left], - &ref_data[left], - block_width - left, block_height - bottom, width); - result += cor_sad(&pic_data[(block_height - bottom) * width], - &ref_data[(block_height - bottom - 1) * width + left], - left, bottom, width); - result += ver_sad(&pic_data[(block_height - bottom) * width + left], - &ref_data[(block_height - bottom - 1) * width + left], - block_width - left, bottom, width); - } else if (bottom && right) { - result += reg_sad(pic_data, - ref_data, - block_width - right, block_height - bottom, width); - result += hor_sad(&pic_data[block_width - right], - &ref_data[block_width - right - 1], - right, block_height - bottom, width); - result += ver_sad(&pic_data[(block_height - bottom) * width], - &ref_data[(block_height - bottom - 1) * width], - block_width - right, bottom, width); - result += cor_sad(&pic_data[(block_height - bottom) * width + block_width - right], - &ref_data[(block_height - bottom - 1) * width + block_width - right - 1], - right, bottom, width); - } else if (top) { - result += ver_sad(pic_data, - &ref_data[top * width], - block_width, top, width); - result += reg_sad(&pic_data[top * width], - &ref_data[top * width], - block_width, block_height - top, width); - } else if (bottom) { - result += reg_sad(pic_data, - ref_data, - block_width, block_height - bottom, width); - result += ver_sad(&pic_data[(block_height - bottom) * width], - &ref_data[(block_height - bottom - 1) * width], - block_width, bottom, width); - } else if (left) { - result += hor_sad(pic_data, - &ref_data[left], - left, block_height, width); - result += reg_sad(&pic_data[left], - &ref_data[left], - block_width - left, block_height, width); - } else if (right) { - result += reg_sad(pic_data, - ref_data, - block_width - right, block_height, width); - result += hor_sad(&pic_data[block_width - right], - &ref_data[block_width - right - 1], - right, block_height, width); - } else { - result += reg_sad(pic_data, ref_data, block_width, block_height, width); - } - - return result; -} - - -unsigned calc_sad(picture *pic, picture *ref, - int pic_x, int pic_y, int ref_x, int ref_y, - int block_width, int block_height) -{ - if (ref_x >= 0 && ref_x <= pic->width - block_width && - ref_y >= 0 && ref_y <= pic->height - block_height) - { - uint8_t *pic_data = &pic->y_data[pic_y * pic->width + pic_x]; - uint8_t *ref_data = &ref->y_data[ref_y * pic->width + ref_x]; - reg_sad(pic_data, ref_data, block_width, block_height, pic->width); - } else { - return general_sad(pic, ref, pic_x, pic_y, ref_x, ref_y, block_width, block_height); - } -} - - typedef struct { int x; int y;