diff --git a/src/search.c b/src/search.c index 2c9d7d8a..93dc7df1 100644 --- a/src/search.c +++ b/src/search.c @@ -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); }