Add a more general cost function to motion search.

This commit is contained in:
Ari Koivula 2013-09-27 15:41:37 +03:00
parent 562a43d541
commit 571fec7c39

View file

@ -28,24 +28,71 @@
#define USE_INTRA_IN_P 0
#define RENDER_CU 0
#define USE_FULL_SEARCH 0
#define USE_CHROMA_IN_MV_SEARCH 0
#define IN_FRAME(x, y, width, height, block) ((x) >= 0 && (y) >= 0 && (x) + (block) <= (width) && (y) + (block) <= (height))
unsigned get_sad(int x, int y, int width, int height, int block, uint8_t *pic_data, uint8_t *ref_data)
/**
* \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)
{
if (!IN_FRAME(x, y, width, height, block)) return 0; // This means invalid, for now.
uint8_t *pic_data, *ref_data;
int width = pic->width;
int height = pic->height;
int block = pic->width;
return 1 + sad(pic_data, &ref_data[y * width + x], block, block, width);
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)) 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, block, 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, block, 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, block, width);
#endif
return result;
}
void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
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);
unsigned cost = get_sad(orig_x + x, orig_y + y, pic->width, pic->height, block_width, pic_data, ref_data);
// 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;
@ -57,7 +104,8 @@ void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
// If initial vector is long, also try the (0, 0) vector just in case.
if (x != 0 || y != 0) {
cost = get_sad(orig_x, orig_y, pic->width, pic->height, block_width, pic_data, ref_data);
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;
@ -85,7 +133,9 @@ void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
y = cur_cu->inter.mv[1];
// above
cost = get_sad(orig_x + x, orig_y + y - step, pic->width, pic->height, block_width, pic_data, ref_data);
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;
@ -93,7 +143,9 @@ void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
}
// left
cost = get_sad(orig_x + x - step, orig_y + y, pic->width, pic->height, block_width, pic_data, ref_data);
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;
@ -101,7 +153,9 @@ void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
}
// right
cost = get_sad(orig_x + x + step, orig_y + y, pic->width, pic->height, block_width, pic_data, ref_data);
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;
@ -109,7 +163,9 @@ void search_mv(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
}
// below
cost = get_sad(orig_x + x, orig_y + y + step, pic->width, pic->height, block_width, pic_data, ref_data);
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;
@ -158,13 +214,13 @@ void search_mv_full(picture *pic, uint8_t *pic_data, uint8_t *ref_data,
step /= 2;
if (step > 0) {
search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y,
x, y - step, depth);
x, y - step, depth);
search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y,
x - step, y, depth);
x - step, y, depth);
search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y,
x + step, y, depth);
x + step, y, depth);
search_mv_full(pic, pic_data, ref_data, cur_cu, step, orig_x, orig_y,
x, y + step, depth);
x, y + step, depth);
}
}
@ -315,7 +371,7 @@ void search_tree(encoder_control *encoder,
cur_cu, 8, x, y,
start_x, start_y, depth);
} else {
search_mv(cur_pic, cur_data, ref_pic->y_data,
search_mv(cur_pic, ref_pic,
cur_cu, x, y,
start_x, start_y, depth);
}