Merge branch 'sad-boundary'

This commit is contained in:
Ari Koivula 2013-10-11 15:38:35 +03:00
commit dba20b2467
9 changed files with 537 additions and 237 deletions

View file

@ -18,7 +18,6 @@
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VS2010\HEVC_encoder.vcxproj">
<Project>{eea3bdd1-8a08-41c1-ba57-e05d5c2cd8ff}</Project>
@ -29,9 +28,7 @@
<Keyword>Win32Proj</Keyword>
<RootNamespace>HEVC_encoder_tests</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
@ -44,9 +41,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -64,16 +59,36 @@
<Import Project="..\Release_Optimizations.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PostBuildEvent>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PostBuildEvent>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<PostBuildEvent>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PostBuildEvent>
<Command>$(TargetPath)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\seatest\src\seatest.c" />
<ClCompile Include="..\..\tests\picture_list_tests.c" />
<ClCompile Include="..\..\tests\sad_tests.cpp" />
<ClCompile Include="..\..\tests\tests_main.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\tests\picture_list_tests.h" />
<ClInclude Include="..\..\tests\sad_tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View file

@ -24,10 +24,16 @@
<ClCompile Include="..\..\tests\picture_list_tests.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\tests\sad_tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\tests\picture_list_tests.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\tests\sad_tests.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -23,9 +23,7 @@
<Keyword>Win32Proj</Keyword>
<RootNamespace>HEVC_interface</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
@ -38,9 +36,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -70,6 +66,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>HEVC_encoder</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PostBuildEvent />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PostBuildEvent />
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\VS2010\HEVC_encoder.vcxproj">
<Project>{eea3bdd1-8a08-41c1-ba57-e05d5c2cd8ff}</Project>

View file

@ -582,6 +582,85 @@ 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)
{
unsigned char ref = *ref_data;
int 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;
}
/**
* \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)
{
int 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;
}
/**
* \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)
{
int 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)
*
@ -596,10 +675,10 @@ uint32_t sad4x4(int16_t *block1, uint32_t stride1,
*
* \returns Sum of Absolute Differences
*/
uint32_t 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) {
@ -610,3 +689,167 @@ uint32_t 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);
}
}

View file

@ -123,8 +123,10 @@ 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);
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);

View file

@ -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) \
@ -36,57 +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 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)
{
uint8_t *pic_data, *ref_data;
int width = pic->width;
int height = pic->height;
unsigned result = 1; // Start from 1 so result is never 0.
// 0 means invalid, for now.
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 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;
}
typedef struct {
int x;
int y;
@ -131,7 +79,7 @@ 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,
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) {
@ -142,7 +90,7 @@ 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,
unsigned cost = calc_sad(pic, ref, orig_x, orig_y,
orig_x, orig_y,
block_width, block_width);
if (cost > 0 && cost < best_cost) {
@ -154,7 +102,7 @@ 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,
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) {
@ -185,7 +133,7 @@ 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,
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) {
@ -202,7 +150,7 @@ 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,
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) {
@ -219,146 +167,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 = 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
*/
@ -500,21 +308,10 @@ 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);
}
}
cur_cu->type = CU_INTER;
cur_cu->inter.mv_dir = 1;

227
tests/sad_tests.cpp Normal file
View file

@ -0,0 +1,227 @@
#include "seatest.h"
#include <stdlib.h>
#include "picture.h"
//////////////////////////////////////////////////////////////////////////
// EXTERNAL FUNCTIONS
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) calc_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)
{
unsigned i;
g_pic = picture_init(8, 8, 1, 1);
for (i = 0; i < 64; ++i) {
g_pic->y_data[i] = pic_data[i] + 48;
}
g_ref = picture_init(8, 8, 1, 1);
for (i = 0; i < 64; ++i) {
g_ref->y_data[i] = ref_data[i] + 48;
}
}
void sad_teardown(void)
{
free(g_pic); g_pic = 0;
free(g_ref); g_ref = 0;
}
//////////////////////////////////////////////////////////////////////////
// OVERLAPPING BOUNDARY TESTS
void test_topleft(void)
{
assert_ulong_equal(
1*(4*4) + (2+4)*(4*4) + 5*(4*4) - 64,
TEST_SAD(-3, -3));
}
void test_top(void)
{
assert_ulong_equal(
(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*(4*4) + (2+6)*(4*4) + 5*(4*4) - 64,
TEST_SAD(3, -3));
}
void test_left(void)
{
assert_ulong_equal(
(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 + 5*(6*6) - 64,
TEST_SAD(0, 0));
}
void test_right(void)
{
assert_ulong_equal(
(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*(4*4) + (4+8)*(4*4) + 5*(4*4) - 64,
TEST_SAD(-3, 3));
}
void test_bottom(void)
{
assert_ulong_equal(
(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*(4*4) + (6+8)*(4*4) + 5*(4*4) - 64,
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)
{
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);
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);
// 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();
}

6
tests/sad_tests.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef SAD_TESTS_H_
#define SAD_TESTS_H_
void sad_tests(void);
#endif

View file

@ -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()