mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 19:24:06 +00:00
Merge branch 'sad-boundary'
This commit is contained in:
commit
dba20b2467
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
249
src/picture.c
249
src/picture.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
213
src/search.c
213
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) \
|
||||
|
@ -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
227
tests/sad_tests.cpp
Normal 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
6
tests/sad_tests.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef SAD_TESTS_H_
|
||||
#define SAD_TESTS_H_
|
||||
|
||||
void sad_tests(void);
|
||||
|
||||
#endif
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue