blob: 612208787e16d5226da525c2c41289136e3c56d4 [file] [log] [blame]
/*
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <math.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <inttypes.h>
#include <malloc.h>
#include <string.h>
#include <png.h>
#include <time.h>
#include "av1/common/spherical_pred.h"
#include "av1/common/common.h"
#include "av1/common/filter.h"
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
namespace {
// The following code reads data from y4m file
// The original code is not from Google, so I will state what interface the rest
// of the test code uses.
typedef void *handle_t;
typedef struct {
/* plane count
* plane stride x4
* plane data x4
*/
} image_t;
typedef struct {
/* pts of picture */
/* image_t, raw data */
} picture_t;
typedef struct {
/* frame width, height, and frame count
*/
} config_t;
/* Most of this is from x264 */
/* YUV4MPEG2 raw 420 yuv file operation */
typedef struct {
/* Basic information filled by the reading functions
file pointer, frame width, height, fps, etc.*/
} y4m_input_t;
// Given a filename, read y4m file header, fill the structs
int open_file_y4m(char *filename, handle_t *handle, config_t *config) {
return 0;
}
// Read the raw data of frame #framenum to pic
int read_frame_y4m(handle_t handle, picture_t *pic, int framenum) { return 0; }
// Close file
int close_file_y4m(handle_t handle) { return 0; }
#define DIFF_THRESHOLD 0.00001
constexpr double pi = 3.141592653589793238462643383279502884;
typedef struct {
double x;
double y;
} PlaneMV;
// Warp the plane coordinate back if out of border
// Flip x if y out of border
void warp_coordinate(int frame_width, int frame_height, int *x, int *y) {
const int height = frame_height - 1;
const int width = frame_width - 1;
if (*y > height || *y < 0) {
*y = *y < 0 ? -(1 + *y % height) : frame_height - *y % height;
*x = *x + frame_width / 2;
}
if (*x > width || *x < 0) {
*x = *x % frame_width;
*x = *x > 0 ? *x : frame_width + *x;
}
}
// Warp sub-pixel plane coordinate
void warp_coordinate_interp(int frame_width, int frame_height, double *x,
double *y) {
const int height = frame_height - 1;
const int width = frame_width - 1;
if (*y > height || *y < 0) {
*y = *y < 0 ? -fmod(*y, height) : frame_height - fmod(*y, height);
*x = *x + frame_width / 2;
}
if (*x > width || *x < 0) {
*x = fmod(*x, frame_width);
*x = *x > 0 ? *x : frame_width + *x;
}
}
// Some of the functions are static in the codebase. So I copied them.
static int get_sad_of_blocks(const uint8_t *cur_block,
const uint8_t *pred_block, int block_width,
int block_height, int cur_block_stride,
int pred_block_stride) {
assert(block_width > 0 && block_height > 0 && cur_block_stride >= 0 &&
pred_block_stride >= 0);
int pos_curr;
int pos_pred;
int ret_sad = 0;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
pos_curr = idx_x + idx_y * cur_block_stride;
pos_pred = idx_x + idx_y * pred_block_stride;
ret_sad += abs((int)cur_block[pos_curr] - (int)pred_block[pos_pred]);
}
}
return ret_sad;
}
/*!\brief Calculate the filter kernel index based on the subpixel coordination
* \param[in] subpel_pos The subpixel coordination
* \param[out] pos_ref The integer coordination to which the filter kernel
* center should align to. If the subpixel coordination
* is with in the range of (0, -0.0625) to the pixel on
* its right, we choose that pixel. Otherwise, we
* choose the pixel on the left of the subpixel.
* \return The kernel index. It is doubled since we only use
* #(0, 2, 4, ... 14) kernels
*/
int cal_kernel_idx(double subpel_pos, int *pos_ref) {
double diff = subpel_pos - floor(subpel_pos);
int idx = (int)round(diff / 0.125);
if (idx >= SUBPEL_SHIFTS / 2) {
idx = idx % (SUBPEL_SHIFTS / 2);
*pos_ref = (int)ceil(subpel_pos);
} else {
*pos_ref = (int)floor(subpel_pos);
}
return idx * 2;
}
// Get the filtered sums of the rows int the 8x8 block centered at the
// input location
void get_interp_x_arr(int x, int y, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height,
const InterpKernel *kernel, int filter_tap,
int x_kernel_idx, double *x_sum_arr) {
int fo = filter_tap / 2 - 1;
int cur_x;
int cur_y;
double coeff = 0;
double sum = 0;
for (int i = 0; i < 8; i++) {
cur_y = y - fo + i;
cur_y = AOMMAX(cur_y, 0);
cur_y = AOMMIN(cur_y, frame_height - 1);
sum = 0;
for (int k = 0; k < filter_tap; k++) {
coeff = kernel[x_kernel_idx][k] / 128.0;
cur_x = x - fo + k;
cur_x = cur_x % frame_width;
cur_x = cur_x >= 0 ? cur_x : frame_width + cur_x;
sum += ref_frame[cur_x + cur_y * ref_frame_stride] * coeff;
}
x_sum_arr[i] = sum;
} // for i
}
void av1_get_pred_plane(int block_x, int block_y, int block_width,
int block_height, double delta_x, double delta_y,
const uint8_t *cur_frame, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height,
int block_stride, uint8_t *cur_block,
uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(cur_block != NULL && pred_block != NULL && block_width > 0 &&
block_height > 0 && block_stride >= block_width);
int pos_block; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
int pos_cur;
int x_current; // X coordiante in current frame
int y_current; // Y coordiante in currrent frame
int x_ref; // X coordinate in reference frame
int y_ref; // Y coordiante in reference frame
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
x_ref = x_current + delta_x;
y_ref = y_current + delta_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
warp_coordinate(frame_width, frame_height, &x_ref, &y_ref);
pos_block = idx_x + idx_y * block_stride;
pos_cur = x_current + y_current * ref_frame_stride;
pos_ref = x_ref + y_ref * ref_frame_stride;
cur_block[pos_block] = cur_frame[pos_cur];
pred_block[pos_block] = ref_frame[pos_ref];
}
}
}
void get_interp_x_arr_plane(int x, int y, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width,
int frame_height, const InterpKernel *kernel,
int filter_tap, int x_kernel_idx,
double *x_sum_arr) {
int fo = filter_tap / 2 - 1;
int cur_x;
int cur_y;
double coeff = 0;
double sum = 0;
for (int i = 0; i < 8; i++) {
cur_y = y - fo + i;
cur_y = AOMMAX(cur_y, 0);
cur_y = AOMMIN(cur_y, frame_height - 1);
sum = 0;
for (int k = 0; k < filter_tap; k++) {
coeff = kernel[x_kernel_idx][k] / 128.0;
cur_x = x - fo + k;
cur_x = cur_x % frame_width;
cur_x = cur_x >= 0 ? cur_x : frame_width + cur_x;
sum += ref_frame[cur_x + cur_y * ref_frame_stride] * coeff;
}
x_sum_arr[i] = sum;
} // for i
}
uint8_t interp_pixel_plane(const uint8_t *ref_frame, int ref_frame_stride,
int frame_width, int frame_height, double subpel_x,
double subpel_y, const InterpKernel *kernel,
int filter_tap) {
double x_sum_arr[8];
double sum = 0;
double coeff = 0;
int x_kernel_idx;
int y_kernel_idx;
int x_ref;
int y_ref;
int pixel;
x_kernel_idx = cal_kernel_idx(subpel_x, &x_ref);
y_kernel_idx = cal_kernel_idx(subpel_y, &y_ref);
get_interp_x_arr_plane(x_ref, y_ref, ref_frame, ref_frame_stride, frame_width,
frame_height, kernel, filter_tap, x_kernel_idx,
x_sum_arr);
// Perform filtering on the column
sum = 0;
for (int k = 0; k < filter_tap; k++) {
coeff = kernel[y_kernel_idx][k] / 128.0;
sum += x_sum_arr[k] * coeff;
}
pixel = (int)round(sum);
pixel = clamp(pixel, 0, 255);
return (uint8_t)pixel;
}
void av1_get_pred_plane_interp_bilinear(
int block_x, int block_y, int block_width, int block_height, double delta_x,
double delta_y, const uint8_t *cur_frame, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height, int block_stride,
uint8_t *cur_block, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(cur_block != NULL && pred_block != NULL && block_width > 0 &&
block_height > 0 && block_stride >= block_width);
int pos_block; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
int pos_cur;
int x_current; // X coordiante in current frame
int y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
x_ref = x_current + delta_x;
y_ref = y_current + delta_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
warp_coordinate_interp(frame_width, frame_height, &x_ref, &y_ref);
pos_block = idx_x + idx_y * block_stride;
pos_cur = x_current + y_current * ref_frame_stride;
// pos_ref = (int)floor(x_ref) + y_ref * ref_frame_stride;
cur_block[pos_block] = cur_frame[pos_cur];
pred_block[pos_block] = interp_pixel_plane(
ref_frame, ref_frame_stride, frame_width, frame_height, x_ref, y_ref,
av1_bilinear_filters, filter_tap);
}
}
}
void av1_get_pred_plane_interp_sub_pel_8(
int block_x, int block_y, int block_width, int block_height, double delta_x,
double delta_y, const uint8_t *cur_frame, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height, int block_stride,
uint8_t *cur_block, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(cur_block != NULL && pred_block != NULL && block_width > 0 &&
block_height > 0 && block_stride >= block_width);
int pos_block; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
int pos_cur;
int x_current; // X coordiante in current frame
int y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
x_ref = x_current + delta_x;
y_ref = y_current + delta_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
warp_coordinate_interp(frame_width, frame_height, &x_ref, &y_ref);
pos_block = idx_x + idx_y * block_stride;
pos_cur = x_current + y_current * ref_frame_stride;
// pos_ref = (int)floor(x_ref) + y_ref * ref_frame_stride;
cur_block[pos_block] = cur_frame[pos_cur];
pred_block[pos_block] = interp_pixel_plane(
ref_frame, ref_frame_stride, frame_width, frame_height, x_ref, y_ref,
av1_sub_pel_filters_8, filter_tap);
}
}
}
void av1_get_pred_plane_interp_sub_pel_8sharp(
int block_x, int block_y, int block_width, int block_height, double delta_x,
double delta_y, const uint8_t *cur_frame, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height, int block_stride,
uint8_t *cur_block, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(cur_block != NULL && pred_block != NULL && block_width > 0 &&
block_height > 0 && block_stride >= block_width);
int pos_block; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
int pos_cur;
int x_current; // X coordiante in current frame
int y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
x_ref = x_current + delta_x;
y_ref = y_current + delta_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
warp_coordinate_interp(frame_width, frame_height, &x_ref, &y_ref);
pos_block = idx_x + idx_y * block_stride;
pos_cur = x_current + y_current * ref_frame_stride;
// pos_ref = (int)floor(x_ref) + y_ref * ref_frame_stride;
cur_block[pos_block] = cur_frame[pos_cur];
pred_block[pos_block] = interp_pixel_plane(
ref_frame, ref_frame_stride, frame_width, frame_height, x_ref, y_ref,
av1_sub_pel_filters_8sharp, filter_tap);
}
}
}
void av1_get_pred_plane_interp_sub_pel_8smooth(
int block_x, int block_y, int block_width, int block_height, double delta_x,
double delta_y, const uint8_t *cur_frame, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height, int block_stride,
uint8_t *cur_block, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(cur_block != NULL && pred_block != NULL && block_width > 0 &&
block_height > 0 && block_stride >= block_width);
int pos_block; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
int pos_cur;
int x_current; // X coordiante in current frame
int y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
x_ref = x_current + delta_x;
y_ref = y_current + delta_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
warp_coordinate_interp(frame_width, frame_height, &x_ref, &y_ref);
pos_block = idx_x + idx_y * block_stride;
pos_cur = x_current + y_current * ref_frame_stride;
// pos_ref = (int)floor(x_ref) + y_ref * ref_frame_stride;
cur_block[pos_block] = cur_frame[pos_cur];
pred_block[pos_block] = interp_pixel_plane(
ref_frame, ref_frame_stride, frame_width, frame_height, x_ref, y_ref,
av1_sub_pel_filters_8smooth, filter_tap);
}
}
}
// Given two index maps, calculate SAD on plane
static int sad_of_blocks_from_idx(const uint8_t *cur_frame,
const uint8_t *ref_frame, int *cur_block_idx,
int *pred_block_idx, int block_width,
int block_height, int cur_block_stride,
int pred_block_stride) {
assert(block_width > 0 && block_height > 0 && cur_block_stride >= 0 &&
pred_block_stride >= 0);
int pos_curr;
int pos_pred;
int ret_sad = 0;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
pos_curr = idx_x + idx_y * cur_block_stride;
pos_pred = idx_x + idx_y * pred_block_stride;
ret_sad += abs(cur_frame[cur_block_idx[pos_curr]] -
ref_frame[pred_block_idx[pos_pred]]);
}
}
return ret_sad;
}
int av1_motion_search_brute_force_plane(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 1;
int temp_sad;
int best_sad;
int delta_x;
int delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane(block_x, block_y, block_width, block_height, 0, 0,
cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -search_range; i <= search_range; i++) {
delta_y = i * search_step;
for (int j = -search_range; j <= search_range; j++) {
delta_x = j * search_step;
av1_get_pred_plane(block_x, block_y, block_width, block_height, delta_x,
delta_y, cur_frame, ref_frame, frame_stride,
frame_width, frame_height, pred_block_stride,
cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
int av1_motion_search_brute_force_plane_interp_bilinear(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *start_mv,
PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 0.125;
int temp_sad;
int best_sad;
double delta_x;
double delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, start_mv->x, start_mv->y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -8; i <= 8; i++) {
delta_y = start_mv->y + i * search_step;
for (int j = -8; j <= 8; j++) {
delta_x = start_mv->x + j * search_step;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
int av1_motion_search_brute_force_plane_interp_sub_pel_8(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *start_mv,
PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 0.125;
int temp_sad;
int best_sad;
double delta_x;
double delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, start_mv->x, start_mv->y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -8; i <= 8; i++) {
delta_y = start_mv->y + i * search_step;
for (int j = -8; j <= 8; j++) {
delta_x = start_mv->x + j * search_step;
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
int av1_motion_search_brute_force_plane_interp_sub_pel_8smooth(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *start_mv,
PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 0.125;
int temp_sad;
int best_sad;
double delta_x;
double delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, start_mv->x, start_mv->y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -8; i <= 8; i++) {
delta_y = start_mv->y + i * search_step;
for (int j = -8; j <= 8; j++) {
delta_x = start_mv->x + j * search_step;
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
int av1_motion_search_brute_force_plane_interp_sub_pel_8sharp(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *start_mv,
PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 0.125;
int temp_sad;
int best_sad;
double delta_x;
double delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, start_mv->x, start_mv->y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -8; i <= 8; i++) {
delta_y = start_mv->y + i * search_step;
for (int j = -8; j <= 8; j++) {
delta_x = start_mv->x + j * search_step;
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
int av1_motion_search_brute_force_plane_interp_filter_search(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *start_mv,
PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step = 0.125;
int temp_sad;
int best_sad;
double delta_x;
double delta_y;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, start_mv->x, start_mv->y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
best_mv->x = 0;
best_mv->y = 0;
for (int i = -8; i <= 8; i++) {
delta_y = start_mv->y + i * search_step;
for (int j = -8; j <= 8; j++) {
delta_x = start_mv->x + j * search_step;
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, delta_x, delta_y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->x = delta_x;
best_mv->y = delta_y;
}
} // for j
} // for i
return best_sad;
}
/* Update Large Diamond Search Pattern shperical motion vectors based on the
* center
* ldsp_mv[1]
* / \
* ldsp_mv[8] ldsp_mv[2]
* / \
* ldsp_mv[7] ldsp_mv[0] ldsp_mv[3]
* \ /
* ldsp_mv[6] ldsp_mv[4]
* \ /
* ldsp_mv[5]
*/
static void update_plane_mv_ldsp(PlaneMV ldsp_mv[9], double search_step) {
ldsp_mv[1].y = ldsp_mv[0].y - 2 * search_step;
ldsp_mv[1].x = ldsp_mv[0].x;
ldsp_mv[2].y = ldsp_mv[0].y - search_step;
ldsp_mv[2].x = ldsp_mv[0].x + search_step;
ldsp_mv[3].y = ldsp_mv[0].y;
ldsp_mv[3].x = ldsp_mv[0].x + 2 * search_step;
ldsp_mv[4].y = ldsp_mv[0].y + search_step;
ldsp_mv[4].x = ldsp_mv[0].x + search_step;
ldsp_mv[5].y = ldsp_mv[0].y + 2 * search_step;
ldsp_mv[5].x = ldsp_mv[0].x;
ldsp_mv[6].y = ldsp_mv[0].y + search_step;
ldsp_mv[6].x = ldsp_mv[0].x - search_step;
ldsp_mv[7].y = ldsp_mv[0].y;
ldsp_mv[7].x = ldsp_mv[0].x - 2 * search_step;
ldsp_mv[8].y = ldsp_mv[0].y - search_step;
ldsp_mv[8].x = ldsp_mv[0].x - search_step;
}
/* Small Diamond Search Pattern on shpere
* sdsp_mv[1]
* / \
* sdsp_mv[4] sdsp_mv[0] sdsp_mv[2]
* \ /
* sdsp_mv[3]
*/
static void update_plane_mv_sdsp(PlaneMV sdsp_mv[5], double search_step) {
sdsp_mv[1].y = sdsp_mv[0].y - search_step;
sdsp_mv[1].x = sdsp_mv[0].x;
sdsp_mv[2].y = sdsp_mv[0].y;
sdsp_mv[2].x = sdsp_mv[0].x + search_step;
sdsp_mv[3].y = sdsp_mv[0].y + search_step;
sdsp_mv[3].x = sdsp_mv[0].x;
sdsp_mv[4].y = sdsp_mv[0].y;
sdsp_mv[4].x = sdsp_mv[0].x - search_step;
}
int av1_motion_search_diamond_plane(int block_x, int block_y, int block_width,
int block_height, const uint8_t *cur_frame,
const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height,
int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane(block_x, block_y, block_width, block_height, 0, 0,
cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane(block_x, block_y, block_width, block_height,
ldsp_mv[i].x, ldsp_mv[i].y, cur_frame, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > 1) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
search_step = 1;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane(block_x, block_y, block_width, block_height,
sdsp_mv[i].x, sdsp_mv[i].y, cur_frame, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
int av1_motion_search_diamond_plane_interp_bilinear(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane_interp_bilinear(block_x, block_y, block_width,
block_height, 0, 0, cur_frame, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
const double min_search_step = 0.125;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > min_search_step) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
int av1_motion_search_diamond_plane_interp_sub_pel_8(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane_interp_sub_pel_8(block_x, block_y, block_width,
block_height, 0, 0, cur_frame, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
const double min_search_step = 0.125;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > min_search_step) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
int av1_motion_search_diamond_plane_interp_sub_pel_8sharp(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, 0, 0, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, pred_block_stride, cur_block,
pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
const double min_search_step = 0.125;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > min_search_step) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
int av1_motion_search_diamond_plane_interp_sub_pel_8smooth(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, 0, 0, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, pred_block_stride, cur_block,
pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
const double min_search_step = 0.125;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > min_search_step) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
int av1_motion_search_diamond_plane_interp_filter_search(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, PlaneMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
PlaneMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
PlaneMV sdsp_mv[5];
int search_step = block_height / 5;
uint8_t cur_block[128 * 128];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
int max_range_y = block_y + search_range;
int min_range_y = block_y - search_range;
int max_range_x = block_x + search_range;
int min_range_x = block_x - search_range;
int temp_sad;
int best_sad;
av1_get_pred_plane_interp_bilinear(block_x, block_y, block_width,
block_height, 0, 0, cur_frame, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
int best_mv_idx = 0;
ldsp_mv[0].y = 0;
ldsp_mv[0].x = 0;
const double min_search_step = 0.125;
do {
update_plane_mv_ldsp(ldsp_mv, search_step);
for (int i = 0; i < 9; i++) {
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].x,
ldsp_mv[i].y, cur_frame, ref_frame, frame_stride, frame_width,
frame_height, pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step > min_search_step) {
search_step *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].y = ldsp_mv[best_mv_idx].y;
ldsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
}
} while (block_y + ldsp_mv[5].y <= max_range_y &&
block_y + ldsp_mv[1].y >= min_range_y &&
block_x + ldsp_mv[3].x <= max_range_x &&
block_x + ldsp_mv[7].x >= min_range_x);
sdsp_mv[0].y = ldsp_mv[best_mv_idx].y;
sdsp_mv[0].x = ldsp_mv[best_mv_idx].x;
best_mv_idx = 0;
update_plane_mv_sdsp(sdsp_mv, search_step);
for (int i = 0; i < 5; i++) {
av1_get_pred_plane_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
pred_block_stride, pred_block_stride);
av1_get_pred_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
av1_get_pred_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].x, sdsp_mv[i].y,
cur_frame, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, cur_block, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, pred_block_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->y = sdsp_mv[best_mv_idx].y;
best_mv->x = sdsp_mv[best_mv_idx].x;
return best_sad;
}
uint8_t interp_pixel_erp(const uint8_t *ref_frame, int ref_frame_stride,
int frame_width, int frame_height, double subpel_x,
double subpel_y, const InterpKernel *kernel,
int filter_tap) {
double x_sum_arr[8];
double sum = 0;
double coeff = 0;
int x_kernel_idx;
int y_kernel_idx;
int x_ref;
int y_ref;
int pixel;
x_kernel_idx = cal_kernel_idx(subpel_x, &x_ref);
y_kernel_idx = cal_kernel_idx(subpel_y, &y_ref);
get_interp_x_arr(x_ref, y_ref, ref_frame, ref_frame_stride, frame_width,
frame_height, kernel, filter_tap, x_kernel_idx, x_sum_arr);
// Perform filtering on the column
sum = 0;
for (int k = 0; k < filter_tap; k++) {
coeff = kernel[y_kernel_idx][k] / 128.0;
sum += x_sum_arr[k] * coeff;
}
pixel = (int)round(sum);
pixel = clamp(pixel, 0, 255);
return (uint8_t)pixel;
}
void av1_get_pred_erp_interp(int block_x, int block_y, int block_width,
int block_height, double delta_phi,
double delta_theta, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width,
int frame_height, int pred_block_stride,
uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x_ref; // X coordinate in reference frame
double subpel_y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x_ref,
&subpel_y_ref);
pos_pred = idx_x + idx_y * pred_block_stride;
pred_block[pos_pred] = interp_pixel_erp(
ref_frame, ref_frame_stride, frame_width, frame_height, subpel_x_ref,
subpel_y_ref, av1_sub_pel_filters_8, filter_tap);
}
} // for idx_y
}
void av1_get_pred_erp_interp_bilinear(int block_x, int block_y, int block_width,
int block_height, double delta_phi,
double delta_theta,
const uint8_t *ref_frame,
int ref_frame_stride, int frame_width,
int frame_height, int pred_block_stride,
uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x_ref; // X coordinate in reference frame
double subpel_y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x_ref,
&subpel_y_ref);
pos_pred = idx_x + idx_y * pred_block_stride;
pred_block[pos_pred] = interp_pixel_erp(
ref_frame, ref_frame_stride, frame_width, frame_height, subpel_x_ref,
subpel_y_ref, av1_bilinear_filters, filter_tap);
}
} // for idx_y
}
void av1_get_pred_erp_interp_sub_pel_8(int block_x, int block_y,
int block_width, int block_height,
double delta_phi, double delta_theta,
const uint8_t *ref_frame,
int ref_frame_stride, int frame_width,
int frame_height, int pred_block_stride,
uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x_ref; // X coordinate in reference frame
double subpel_y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x_ref,
&subpel_y_ref);
pos_pred = idx_x + idx_y * pred_block_stride;
pred_block[pos_pred] = interp_pixel_erp(
ref_frame, ref_frame_stride, frame_width, frame_height, subpel_x_ref,
subpel_y_ref, av1_sub_pel_filters_8, filter_tap);
}
} // for idx_y
}
void av1_get_pred_erp_interp_sub_pel_8sharp(
int block_x, int block_y, int block_width, int block_height,
double delta_phi, double delta_theta, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height,
int pred_block_stride, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x_ref; // X coordinate in reference frame
double subpel_y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x_ref,
&subpel_y_ref);
pos_pred = idx_x + idx_y * pred_block_stride;
pred_block[pos_pred] = interp_pixel_erp(
ref_frame, ref_frame_stride, frame_width, frame_height, subpel_x_ref,
subpel_y_ref, av1_sub_pel_filters_8sharp, filter_tap);
}
} // for idx_y
}
void av1_get_pred_erp_interp_sub_pel_8smooth(
int block_x, int block_y, int block_width, int block_height,
double delta_phi, double delta_theta, const uint8_t *ref_frame,
int ref_frame_stride, int frame_width, int frame_height,
int pred_block_stride, uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x_ref; // X coordinate in reference frame
double subpel_y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
const int filter_tap = 8;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x_ref,
&subpel_y_ref);
pos_pred = idx_x + idx_y * pred_block_stride;
pred_block[pos_pred] = interp_pixel_erp(
ref_frame, ref_frame_stride, frame_width, frame_height, subpel_x_ref,
subpel_y_ref, av1_sub_pel_filters_8smooth, filter_tap);
}
} // for idx_y
}
int av1_motion_search_brute_force_erp_interp(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
const double search_step_phi = PI / frame_height;
const double search_step_theta = 2 * PI / frame_width;
double delta_phi;
double delta_theta;
int temp_sad;
int best_sad;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
av1_get_pred_erp_interp(block_x, block_y, block_width, block_height, 0, 0,
ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
best_mv->phi = 0;
best_mv->theta = 0;
for (int i = -search_range; i <= search_range; i++) {
delta_phi = i * search_step_phi;
for (int j = -search_range; j <= search_range; j++) {
delta_theta = j * search_step_theta;
// cal_delta_theta(block_x, block_y, 10, frame_width, frame_height,
// delta_phi, &delta_theta);
av1_get_pred_erp_interp(block_x, block_y, block_width, block_height,
delta_phi, delta_theta, ref_frame, frame_stride,
frame_width, frame_height, pred_block_stride,
pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv->phi = delta_phi;
best_mv->theta = delta_theta;
}
} // for j
} // for i
return best_sad;
}
/* Update Large Diamond Search Pattern shperical motion vectors based on the
* center
* ldsp_mv[1]
* / \
* ldsp_mv[8] ldsp_mv[2]
* / \
* ldsp_mv[7] ldsp_mv[0] ldsp_mv[3]
* \ /
* ldsp_mv[6] ldsp_mv[4]
* \ /
* ldsp_mv[5]
*/
static void update_sphere_mv_ldsp(SphereMV ldsp_mv[9], double search_step_phi,
double search_step_theta) {
ldsp_mv[1].phi = ldsp_mv[0].phi - 2 * search_step_phi;
ldsp_mv[1].theta = ldsp_mv[0].theta;
ldsp_mv[2].phi = ldsp_mv[0].phi - search_step_phi;
ldsp_mv[2].theta = ldsp_mv[0].theta + search_step_theta;
ldsp_mv[3].phi = ldsp_mv[0].phi;
ldsp_mv[3].theta = ldsp_mv[0].theta + 2 * search_step_theta;
ldsp_mv[4].phi = ldsp_mv[0].phi + search_step_phi;
ldsp_mv[4].theta = ldsp_mv[0].theta + search_step_theta;
ldsp_mv[5].phi = ldsp_mv[0].phi + 2 * search_step_phi;
ldsp_mv[5].theta = ldsp_mv[0].theta;
ldsp_mv[6].phi = ldsp_mv[0].phi + search_step_phi;
ldsp_mv[6].theta = ldsp_mv[0].theta - search_step_theta;
ldsp_mv[7].phi = ldsp_mv[0].phi;
ldsp_mv[7].theta = ldsp_mv[0].theta - 2 * search_step_theta;
ldsp_mv[8].phi = ldsp_mv[0].phi - search_step_phi;
ldsp_mv[8].theta = ldsp_mv[0].theta - search_step_theta;
}
/* Small Diamond Search Pattern on shpere
* sdsp_mv[1]
* / \
* sdsp_mv[4] sdsp_mv[0] sdsp_mv[2]
* \ /
* sdsp_mv[3]
*/
static void update_sphere_mv_sdsp(SphereMV sdsp_mv[5], double search_step_phi,
double search_step_theta) {
sdsp_mv[1].phi = sdsp_mv[0].phi - search_step_phi;
sdsp_mv[1].theta = sdsp_mv[0].theta;
sdsp_mv[2].phi = sdsp_mv[0].phi;
sdsp_mv[2].theta = sdsp_mv[0].theta + search_step_theta;
sdsp_mv[3].phi = sdsp_mv[0].phi + search_step_phi;
sdsp_mv[3].theta = sdsp_mv[0].theta;
sdsp_mv[4].phi = sdsp_mv[0].phi;
sdsp_mv[4].theta = sdsp_mv[0].theta - search_step_theta;
}
int av1_motion_search_diamond_erp_interp(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi = 0.125 * PI / frame_height;
double search_step_theta = 0.125 * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi = start_phi + search_range * PI / frame_height;
double min_range_phi = start_phi - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
do {
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
for (int i = 0; i < 9; i++) {
// cal_delta_theta(block_x, block_y, 10, frame_width, frame_height,
// ldsp_mv[i].phi, &ldsp_mv[i].theta);
av1_get_pred_erp_interp(block_x, block_y, block_width, block_height,
ldsp_mv[i].phi, ldsp_mv[i].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > PI / frame_height &&
search_step_theta > 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
continue;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
} while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta);
sdsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
sdsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
search_step_phi = PI / frame_height;
search_step_theta = 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
for (int i = 0; i < 5; i++) {
av1_get_pred_erp(block_x, block_y, block_width, block_height,
sdsp_mv[i].phi, sdsp_mv[i].theta, ref_frame, frame_stride,
frame_width, frame_height, pred_block_stride, pred_block);
temp_sad = get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_bilinear(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
// printf("Diamond ERP interp search step phi: %f, theta: %f\n",
// search_step_phi,
// search_step_theta);
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->theta - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_bilinear(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <= max_range_theta &&
start_theta + sdsp_mv[4].theta >= min_range_theta) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
// printf("Diamond ERP interp search step phi: %f, theta: %f\n",
// search_step_phi,
// search_step_theta);
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->theta - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <= max_range_theta &&
start_theta + sdsp_mv[4].theta >= min_range_theta) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8sharp(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
// printf("Diamond ERP interp search step phi: %f, theta: %f\n",
// search_step_phi,
// search_step_theta);
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->theta - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <= max_range_theta &&
start_theta + sdsp_mv[4].theta >= min_range_theta) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8smooth(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
// printf("Diamond ERP interp search step phi: %f, theta: %f\n",
// search_step_phi,
// search_step_theta);
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->theta - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <= max_range_theta &&
start_theta + sdsp_mv[4].theta >= min_range_theta) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_filter_search(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
// printf("Diamond ERP interp search step phi: %f, theta: %f\n",
// search_step_phi,
// search_step_theta);
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->theta - search_range * PI / frame_height;
double max_range_theta = start_theta + search_range * 2 * PI / frame_height;
double min_range_theta = start_theta - search_range * 2 * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_bilinear(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <= max_range_theta &&
start_theta + ldsp_mv[7].theta >= min_range_theta) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp(ldsp_mv, search_step_phi, search_step_theta);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp(sdsp_mv, search_step_phi, search_step_theta);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <= max_range_theta &&
start_theta + sdsp_mv[4].theta >= min_range_theta) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
void av1_get_pred_erp(int block_x, int block_y, int block_width,
int block_height, double delta_phi, double delta_theta,
const uint8_t *ref_frame, int ref_frame_stride,
int frame_width, int frame_height, int pred_block_stride,
uint8_t *pred_block) {
assert(ref_frame != NULL && frame_width > 0 && frame_height > 0 &&
ref_frame_stride >= frame_width);
assert(pred_block != NULL && block_width > 0 && block_height > 0 &&
pred_block_stride >= block_width);
int pos_pred; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector block_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &block_v_prime);
av1_carte_vectors_cross_product(&block_v, &block_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &block_v_prime);
// Avoid floating point precision issues
product = AOMMAX(product, -1.0);
product = AOMMIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * PI;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * PI;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &x_ref, &y_ref);
x_ref = round(x_ref);
x_ref = (int)x_ref == frame_width ? 0 : x_ref;
y_ref = round(y_ref);
y_ref = (int)y_ref == frame_height ? frame_height - 1 : y_ref;
pos_pred = idx_x + idx_y * pred_block_stride;
pos_ref = (int)x_ref + (int)y_ref * ref_frame_stride;
pred_block[pos_pred] = ref_frame[pos_ref];
}
}
}
/* Calculate the scale of theta based on the current phi.
* Makes the search/filter pattern on the latitude sparse as the position moves
* toward polars. Will be used for adjusting searching step, searching range,
* and filtering.
*/
static double cal_theta_scale(double phi) {
const double max_scale = 10.0;
if (cos(phi) > 0.00001) {
return AOMMIN(max_scale, 1 / cos(phi));
} else {
return max_scale;
}
}
static double cal_range_theta(int search_range, int frame_width, double phi) {
return search_range * cal_theta_scale(phi) * 2 * PI / frame_width;
}
/* Update Large Diamond Search Pattern shperical motion vectors based on the
* center
* ldsp_mv[1]
* / \
* ldsp_mv[8] ldsp_mv[2]
* / \
* ldsp_mv[7] ldsp_mv[0] ldsp_mv[3]
* \ /
* ldsp_mv[6] ldsp_mv[4]
* \ /
* ldsp_mv[5]
*/
static void update_sphere_mv_ldsp_interp_scale(SphereMV ldsp_mv[9],
double search_step_phi,
double search_step_theta,
double block_phi) {
double magnified_step_theta;
ldsp_mv[1].phi = ldsp_mv[0].phi - 2 * search_step_phi;
ldsp_mv[1].theta = ldsp_mv[0].theta;
ldsp_mv[2].phi = ldsp_mv[0].phi - search_step_phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[2].phi);
ldsp_mv[2].theta = ldsp_mv[0].theta + magnified_step_theta;
ldsp_mv[3].phi = ldsp_mv[0].phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[3].phi);
ldsp_mv[3].theta = ldsp_mv[0].theta + 2 * magnified_step_theta;
ldsp_mv[4].phi = ldsp_mv[0].phi + search_step_phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[4].phi);
ldsp_mv[4].theta = ldsp_mv[0].theta + magnified_step_theta;
ldsp_mv[5].phi = ldsp_mv[0].phi + 2 * search_step_phi;
ldsp_mv[5].theta = ldsp_mv[0].theta;
ldsp_mv[6].phi = ldsp_mv[0].phi + search_step_phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[6].phi);
ldsp_mv[6].theta = ldsp_mv[0].theta - magnified_step_theta;
ldsp_mv[7].phi = ldsp_mv[0].phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[7].phi);
ldsp_mv[7].theta = ldsp_mv[0].theta - 2 * magnified_step_theta;
ldsp_mv[8].phi = ldsp_mv[0].phi - search_step_phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + ldsp_mv[8].phi);
ldsp_mv[8].theta = ldsp_mv[0].theta - magnified_step_theta;
}
/* Small Diamond Search Pattern on shpere
* sdsp_mv[1]
* / \
* sdsp_mv[4] sdsp_mv[0] sdsp_mv[2]
* \ /
* sdsp_mv[3]
*/
static void update_sphere_mv_sdsp_interp_scale(SphereMV sdsp_mv[5],
double search_step_phi,
double search_step_theta,
double block_phi) {
double magnified_step_theta;
sdsp_mv[1].phi = sdsp_mv[0].phi - search_step_phi;
sdsp_mv[1].theta = sdsp_mv[0].theta;
sdsp_mv[2].phi = sdsp_mv[0].phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + sdsp_mv[2].phi);
sdsp_mv[2].theta = sdsp_mv[0].theta + magnified_step_theta;
sdsp_mv[3].phi = sdsp_mv[0].phi + search_step_phi;
sdsp_mv[3].theta = sdsp_mv[0].theta;
sdsp_mv[4].phi = sdsp_mv[0].phi;
magnified_step_theta =
search_step_theta * cal_theta_scale(block_phi + sdsp_mv[4].phi);
sdsp_mv[4].theta = sdsp_mv[0].theta - magnified_step_theta;
}
int av1_motion_search_diamond_erp_interp_bilinear_scale(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->phi - search_range * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_bilinear(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[3].phi) &&
start_theta + ldsp_mv[7].theta >=
start_theta + start_mv->theta -
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[7].phi)) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp_interp_scale(sdsp_mv, search_step_phi,
search_step_theta, start_phi);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[2].phi) &&
start_theta + sdsp_mv[4].theta >=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[4].phi)) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8_scale(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->phi - search_range * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[3].phi) &&
start_theta + ldsp_mv[7].theta >=
start_theta + start_mv->theta -
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[7].phi)) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp_interp_scale(sdsp_mv, search_step_phi,
search_step_theta, start_phi);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[2].phi) &&
start_theta + sdsp_mv[4].theta >=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[4].phi)) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8sharp_scale(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->phi - search_range * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[3].phi) &&
start_theta + ldsp_mv[7].theta >=
start_theta + start_mv->theta -
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[7].phi)) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp_interp_scale(sdsp_mv, search_step_phi,
search_step_theta, start_phi);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[2].phi) &&
start_theta + sdsp_mv[4].theta >=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[4].phi)) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_sub_pel_8smooth_scale(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->phi - search_range * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[3].phi) &&
start_theta + ldsp_mv[7].theta >=
start_theta + start_mv->theta -
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[7].phi)) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp_interp_scale(sdsp_mv, search_step_phi,
search_step_theta, start_phi);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[2].phi) &&
start_theta + sdsp_mv[4].theta >=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[4].phi)) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
int av1_motion_search_diamond_erp_interp_filter_search_scale(
int block_x, int block_y, int block_width, int block_height,
const uint8_t *cur_frame, const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
const SphereMV *start_mv, SphereMV *best_mv) {
assert(cur_frame != NULL && ref_frame != NULL && best_mv != NULL);
assert(block_width > 0 && block_height > 0 && block_width <= 128 &&
block_height <= 128 && block_x >= 0 && block_y >= 0 &&
frame_width > 0 && frame_height > 0);
assert(search_range > 0);
// Large Diamond Search Pattern on shpere
SphereMV ldsp_mv[9];
// Small Diamond Search Pattern on shpere
SphereMV sdsp_mv[5];
double search_step_phi =
AOMMIN(0.25 * block_height, 0.25 * search_range) * PI / frame_height;
double search_step_theta =
AOMMIN(0.25 * block_width, 0.25 * search_range) * 2 * PI / frame_width;
const uint8_t *cur_block = &cur_frame[block_x + block_y * frame_stride];
uint8_t pred_block[128 * 128];
const int pred_block_stride = 128;
double start_phi;
double start_theta;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&start_phi, &start_theta);
double max_range_phi =
start_phi + start_mv->phi + search_range * PI / frame_height;
double min_range_phi =
start_phi + start_mv->phi - search_range * PI / frame_height;
int best_mv_idx = 0;
ldsp_mv[0].phi = start_mv->phi;
ldsp_mv[0].theta = start_mv->theta;
int temp_sad;
int best_sad;
av1_get_pred_erp_interp_bilinear(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad = get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(block_x, block_y, block_width, block_height,
ldsp_mv[0].phi, ldsp_mv[0].theta, ref_frame,
frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[0].phi,
ldsp_mv[0].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
best_sad =
AOMMIN(best_sad,
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride));
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
const double min_scale = 0.125;
while (start_phi + ldsp_mv[5].phi <= max_range_phi &&
start_phi + ldsp_mv[1].phi >= min_range_phi &&
start_theta + ldsp_mv[3].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[3].phi) &&
start_theta + ldsp_mv[7].theta >=
start_theta + start_mv->theta -
cal_range_theta(search_range, frame_width,
start_phi + ldsp_mv[7].phi)) {
for (int i = 0; i < 9; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, ldsp_mv[i].phi,
ldsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
if (best_mv_idx == 0) {
if (search_step_phi > min_scale * PI / frame_height &&
search_step_theta > min_scale * 2 * PI / frame_height) {
search_step_phi *= 0.5;
search_step_theta *= 0.5;
} else {
break;
}
} else {
ldsp_mv[0].phi = ldsp_mv[best_mv_idx].phi;
ldsp_mv[0].theta = ldsp_mv[best_mv_idx].theta;
best_mv_idx = 0;
}
update_sphere_mv_ldsp_interp_scale(ldsp_mv, search_step_phi,
search_step_theta, start_phi);
}
sdsp_mv[0].phi = ldsp_mv[0].phi;
sdsp_mv[0].theta = ldsp_mv[0].theta;
best_mv_idx = 0;
search_step_phi = min_scale * PI / frame_height;
search_step_theta = min_scale * 2 * PI / frame_width;
update_sphere_mv_sdsp_interp_scale(sdsp_mv, search_step_phi,
search_step_theta, start_phi);
if (start_phi + sdsp_mv[3].phi <= max_range_phi &&
start_phi + sdsp_mv[1].phi >= min_range_phi &&
start_theta + sdsp_mv[2].theta <=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[2].phi) &&
start_theta + sdsp_mv[4].theta >=
start_theta + start_mv->theta +
cal_range_theta(search_range, frame_width,
start_phi + sdsp_mv[4].phi)) {
for (int i = 0; i < 5; i++) {
av1_get_pred_erp_interp_bilinear(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
get_sad_of_blocks(cur_block, pred_block, block_width, block_height,
frame_stride, pred_block_stride);
av1_get_pred_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
av1_get_pred_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, sdsp_mv[i].phi,
sdsp_mv[i].theta, ref_frame, frame_stride, frame_width, frame_height,
pred_block_stride, pred_block);
temp_sad =
AOMMIN(temp_sad, get_sad_of_blocks(cur_block, pred_block, block_width,
block_height, frame_stride,
pred_block_stride));
if (temp_sad < best_sad) {
best_sad = temp_sad;
best_mv_idx = i;
}
} // for
}
best_mv->phi = sdsp_mv[best_mv_idx].phi;
best_mv->theta = sdsp_mv[best_mv_idx].theta;
return best_sad;
}
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
// Given pixels in y, write a bmp file with indices in highlight higlighted
void write_bmp(char *filename, int width, int height, uint8_t *y,
int *highlight, int block_width, int block_height,
int block_stride) {
int Y;
int length = 3 * width * height;
char tag[] = { 'B', 'M' };
int header[] = {
0, // File size... update at the end.
0, 0x36, 0x28, width, height, // Image dimensions in pixels
0x180001, 0, 0, 0x002e23, 0x002e23, 0, 0,
};
// Update file size: just the sum of the sizes of the arrays
// we write to disk.
header[0] = sizeof(tag) + sizeof(header) + length;
FILE *fp = fopen(filename, "w+");
fwrite(&tag, sizeof(tag), 1, fp);
fwrite(&header, sizeof(header), 1, fp);
uint8_t *lume = (uint8_t *)malloc(width * height * sizeof(*y));
for (int i = 0; i < width * height; i++) {
lume[i] = y[i] * 0.5;
}
for (int j = 0; j < block_height; j++) {
for (int i = 0; i < block_width; i++) {
lume[highlight[j * block_stride + i]] *= 2;
}
}
for (int j = height - 1; j >= 0; j--) {
for (int i = 0; i < width; i++) {
Y = lume[i + j * width];
fwrite(&Y, sizeof(tag[0]), 1, fp);
fwrite(&Y, sizeof(tag[0]), 1, fp);
fwrite(&Y, sizeof(tag[0]), 1, fp);
}
}
fclose(fp);
free(lume);
}
// Given block coordiante and ERP motion vector, get the indices of pixels in
// the block and the reference block. The result is for write_bmp.
void get_pred_block_idx(int block_x, int block_y, int block_width,
int block_height, double delta_phi, double delta_theta,
int frame_stride, int frame_width, int frame_height,
int pred_block_stride, int block[], int pred_block[]) {
for (int j = 0; j < block_height; j++) {
for (int i = 0; i < block_width; i++) {
block[j * pred_block_stride + i] =
block_x + i + (block_y + j) * frame_stride;
}
}
int pos_pred; // Offset in pred_block buffer
int pos_ref; // Offset in ref_frame buffer
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
PolarVector block_polar;
CartesianVector block_v;
CartesianVector blcok_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += delta_phi;
block_polar.theta += delta_theta;
av1_sphere_polar_to_carte(&block_polar, &blcok_v_prime);
av1_carte_vectors_cross_product(&block_v, &blcok_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &blcok_v_prime);
// Avoid floating point precision issues
product = MAX(product, -1.0);
product = MIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * pi;
// v_prime_polar.theta -= pi;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &x_ref, &y_ref);
x_ref = round(x_ref);
x_ref = x_ref == frame_width ? 0 : x_ref;
y_ref = round(y_ref);
y_ref = y_ref == frame_height ? frame_height - 1 : y_ref;
pos_pred = idx_x + idx_y * pred_block_stride;
pos_ref = (int)x_ref + (int)y_ref * frame_stride;
pred_block[pos_pred] = pos_ref;
}
}
}
static char *filepaths[] = {
"360test.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/AerialCity_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Balboa_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/BranCastle_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Broadway_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Gaslamp_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Harbor_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/KiteFlite_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Landing_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/PoleVault_le_960P.y4m",
"/usr/local/google/home/yaoyaogoogle/Downloads/Trolley_960P.y4m",
};
static char *output_filepaths[] = {
"./whole_frame_analyze/360test/", "./whole_frame_analyze/AerialCity/",
"./whole_frame_analyze/Balboa/", "./whole_frame_analyze/BranCastle/",
"./whole_frame_analyze/Broadway/", "./whole_frame_analyze/Gaslamp/",
"./whole_frame_analyze/Harbor/", "./whole_frame_analyze/KiteFlite/",
"./whole_frame_analyze/Landing/", "./whole_frame_analyze/PoleVault/",
"./whole_frame_analyze/Trolley/",
};
typedef enum {
TEST360,
ARIALCITY960,
BALBOA960,
BRANCASTLE960,
BROADWAY960,
GASLAMP960,
HARBOR960,
KITEFLITE960,
LANDING960,
POLEVAULT960,
TROLLEY960,
} FILENAME;
typedef struct {
FILENAME filename;
int cur_frame_no;
int ref_frame_no;
int block_x;
int block_y;
int block_width;
int block_height;
int search_range;
} TestConfig;
// Given block and frame info, highlight the motion search result
static void motion_search_test(const TestConfig *test_config) {
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, test_config->ref_frame_no);
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
double ref_block_x;
double ref_block_y;
double block_phi;
double block_theta;
int pred_block[128 * 128];
int cur_block[128 * 128];
const int block_stride = 128;
clock_t start, end;
double cpu_time_used;
int sad;
char *filename = basename(filepaths[test_config->filename]);
char output[80];
printf("File path: %s\n", filepaths[test_config->filename]);
printf("Current block: (%d, %d), size: (%d, %d), in frame %d\n",
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, test_config->cur_frame_no);
start = clock();
sad = av1_motion_search_brute_force_plane(
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, cur_pic.img.plane[0], ref_pic.img.plane[0],
handle->width, handle->width, handle->height, test_config->search_range,
&best_plane_mv);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf(
"Plane bruteforce. Best SAD: %d at (%d, %d) in frame %d. Processing "
"time: %f second(s)\n",
sad, test_config->block_x + best_plane_mv.x,
test_config->block_y + best_plane_mv.y, test_config->ref_frame_no,
cpu_time_used);
start = clock();
sad = av1_motion_search_diamond_plane(
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, cur_pic.img.plane[0], ref_pic.img.plane[0],
handle->width, handle->width, handle->height, test_config->search_range,
&best_plane_mv);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf(
"Plane diamond. Best SAD: %d at (%d, %d) in frame %d. Processing time: "
"%f second(s)\n",
sad, test_config->block_x + best_plane_mv.x,
test_config->block_y + best_plane_mv.y, test_config->ref_frame_no,
cpu_time_used);
av1_plane_to_sphere_erp(test_config->block_x, test_config->block_y,
handle->width, handle->height, &block_phi,
&block_theta);
start = clock();
sad = av1_motion_search_brute_force_erp(
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, cur_pic.img.plane[0], ref_pic.img.plane[0],
handle->width, handle->width, handle->height, test_config->search_range,
&best_sphere_mv);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
av1_sphere_to_plane_erp(block_phi + best_sphere_mv.phi,
block_theta + best_sphere_mv.theta, handle->width,
handle->height, &ref_block_x, &ref_block_y);
printf(
"Sphere bruteforce. Best SAD: %d at Phi: %f, and Theta: %f (%f, %f) in"
" frame %d. Processing time: % f second(s)\n ",
sad, best_sphere_mv.phi, best_sphere_mv.theta, ref_block_x, ref_block_y,
test_config->ref_frame_no, cpu_time_used);
get_pred_block_idx(test_config->block_x, test_config->block_y,
test_config->block_width, test_config->block_height,
best_sphere_mv.phi, best_sphere_mv.theta, handle->width,
handle->width, handle->height, block_stride, cur_block,
pred_block);
int sad_bruteforce_erp = sad_of_blocks_from_idx(
cur_pic.img.plane[0], ref_pic.img.plane[0], cur_block, pred_block,
test_config->block_width, test_config->block_height, block_stride,
block_stride);
snprintf(output, sizeof(output), "%.*s_%d.bmp", strlen(filename) - 4,
filename, test_config->cur_frame_no);
write_bmp(output, handle->width, handle->height, cur_pic.img.plane[0],
cur_block, test_config->block_width, test_config->block_height,
block_stride);
snprintf(output, sizeof(output), "%.*s_%d_to_%d_bruteforce_erp.bmp",
strlen(filename) - 4, filename, test_config->cur_frame_no,
test_config->ref_frame_no);
write_bmp(output, handle->width, handle->height, ref_pic.img.plane[0],
pred_block, test_config->block_width, test_config->block_height,
block_stride);
start = clock();
sad = av1_motion_search_diamond_erp(
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, cur_pic.img.plane[0], ref_pic.img.plane[0],
handle->width, handle->width, handle->height, test_config->search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
av1_sphere_to_plane_erp(block_phi + best_sphere_mv.phi,
block_theta + best_sphere_mv.theta, handle->width,
handle->height, &ref_block_x, &ref_block_y);
printf(
"Sphere diamond. Best SAD: %d at Phi: %f, and Theta: %f (%f, %f) in "
"frame %d. Processing time: "
"%f second(s)\n\n",
sad, best_sphere_mv.phi, best_sphere_mv.theta, ref_block_x, ref_block_y,
test_config->ref_frame_no, cpu_time_used);
get_pred_block_idx(test_config->block_x, test_config->block_y,
test_config->block_width, test_config->block_height,
best_sphere_mv.phi, best_sphere_mv.theta, handle->width,
handle->width, handle->height, block_stride, cur_block,
pred_block);
snprintf(output, sizeof(output), "%.*s_%d_to_%d_diamond_erp.bmp",
strlen(filename) - 4, filename, test_config->cur_frame_no,
test_config->ref_frame_no);
write_bmp(output, handle->width, handle->height, ref_pic.img.plane[0],
pred_block, test_config->block_width, test_config->block_height,
block_stride);
free(cur_pic.img.plane[0]);
free(cur_pic.img.plane[1]);
free(cur_pic.img.plane[2]);
free(ref_pic.img.plane[0]);
free(ref_pic.img.plane[1]);
free(ref_pic.img.plane[2]);
close_file_y4m((handle_t)handle);
}
TEST(SphericalMappingTest, EquiMotionSearchTest) {
// TestConfig configs[] = {
// { ARIALCITY960, 60, 65, 1637, 665, 32, 32, 50 },
// { BALBOA960, 180, 185, 514, 187, 128, 128, 50 },
// { BRANCASTLE960, 60, 65, 914, 398, 64, 64, 50 },
// { BROADWAY960, 80, 85, 1518, 570, 64, 64, 50 },
// { GASLAMP960, 210, 215, 1150, 500, 64, 64, 50 },
// { HARBOR960, 1, 5, 50, 490, 64, 64, 50 },
// { KITEFLITE960, 15, 20, 520, 425, 32, 32, 50 },
// { LANDING960, 90, 95, 828, 212, 128, 128, 50 },
// { POLEVAULT960, 30, 35, 328, 800, 128, 128, 50 },
// { TROLLEY960, 90, 95, 1649, 387, 128, 128, 50 },
// };
// motion_search_test(&configs[9]);
// TestConfig configs[] = {
// { ARIALCITY960, 60, 65, 0, 0, 32, 32, 50 },
// { BALBOA960, 180, 185, 0, 0, 128, 128, 50 },
// { BRANCASTLE960, 60, 65, 0, 0, 64, 64, 50 },
// { BROADWAY960, 80, 85, 0, 0, 64, 64, 50 },
// { GASLAMP960, 210, 215, 0, 0, 64, 64, 50 },
// { HARBOR960, 1, 5, 0, 0, 64, 64, 50 },
// { KITEFLITE960, 15, 20, 0, 0, 32, 32, 50 },
// { LANDING960, 90, 95, 0, 0, 128, 128, 50 },
// { POLEVAULT960, 30, 35, 0, 0, 128, 128, 50 },
// { TROLLEY960, 90, 95, 0, 0, 128, 128, 50 },
// };
// TestConfig configs[] = {
// { ARIALCITY960, 60, 60, 1637, 665, 32, 32, 50 },
// { BALBOA960, 180, 180, 514, 187, 128, 128, 50 },
// { BRANCASTLE960, 60, 60, 914, 398, 64, 64, 50 },
// { BROADWAY960, 80, 80, 1518, 570, 64, 64, 50 },
// { GASLAMP960, 210, 210, 1150, 500, 64, 64, 50 },
// { HARBOR960, 1, 1, 50, 490, 64, 64, 50 },
// { KITEFLITE960, 15, 15, 520, 425, 32, 32, 50 },
// { LANDING960, 90, 90, 828, 212, 128, 128, 50 },
// { POLEVAULT960, 30, 30, 328, 800, 128, 128, 50 },
// { TROLLEY960, 90, 90, 1649, 387, 128, 128, 50 },
// };
// TestConfig configs[] = {
// { ARIALCITY960, 60, 60, 0, 0, 128, 128, 20 },
// { ARIALCITY960, 60, 60, 1920 / 4, 0, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 / 2, 0, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 / 4 * 3, 0, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 - 128, 0, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 960 / 2, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 / 2, 960 / 2, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 - 128, 960 / 2, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 960 - 128, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 / 2, 960 - 128, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 1920 - 128, 960 - 128, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 0, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 1, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 2, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 923, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 924, 32, 32, 20 },
// { ARIALCITY960, 60, 60, 0, 952, 8, 8, 20 },
// };
TestConfig configs[] = {
{ ARIALCITY960, 60, 60, 0, 0, 128, 128, 20 },
{ BALBOA960, 60, 60, 0, 0, 128, 128, 20 },
{ BRANCASTLE960, 60, 60, 0, 0, 128, 128, 20 },
{ BROADWAY960, 60, 60, 0, 0, 128, 128, 20 },
{ GASLAMP960, 60, 60, 0, 0, 128, 128, 20 },
{ HARBOR960, 60, 60, 0, 0, 128, 128, 20 },
{ KITEFLITE960, 60, 60, 0, 0, 128, 128, 20 },
{ LANDING960, 60, 60, 0, 0, 128, 128, 20 },
{ POLEVAULT960, 60, 60, 0, 0, 128, 128, 20 },
{ TROLLEY960, 60, 60, 0, 0, 128, 128, 20 },
};
for (int i = 0; i < 10; i++) {
motion_search_test(&configs[i]);
}
// motion_search_test(&configs[0]);
// motion_search_test(&configs[16]);
}
// Motion search for multiple blocks in the frame. Print average SAD and other
// info.
static void whole_frame_motion_search_test(const TestConfig *test_config) {
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, test_config->ref_frame_no);
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
int block_x;
int block_y;
int block_step_x = handle->width / 50;
int block_step_y = handle->height / 50;
int avg_sad_plane_bruteforce = 0;
int avg_sad_plane_diamond = 0;
int avg_sad_erp_bruteforce_p2p = 0;
int avg_sad_erp_bruteforce_interp = 0;
int avg_sad_erp_diamond_interp = 0;
int avg_sad_erp_diamond_p2p = 0;
int sad_plane_bruteforce = 0;
int sad_plane_diamond = 0;
int sad_erp_bruteforce_p2p = 0;
int sad_erp_bruteforce_interp = 0;
int sad_erp_diamond_interp = 0;
int sad_erp_diamond_p2p = 0;
int block_count = 0;
int block_count_diamond_interp_better = 0;
int block_count_bruteforce_interp_better = 0;
int block_count_bruteforce_erp_better = 0;
int block_count_diamond_erp_better = 0;
clock_t start, end;
double cpu_time_used;
double block_phi;
double block_theta;
double plane_phi;
double plane_theta;
printf("File path: %s\n", filepaths[test_config->filename]);
printf("Current frame: %d, reference frame: %d\n", test_config->cur_frame_no,
test_config->ref_frame_no);
printf("Block size: %dx%d, search range: %d\n", test_config->block_width,
test_config->block_height, test_config->search_range);
start = clock();
for (block_y = 0; block_y + test_config->block_height < handle->height;
block_y += block_step_y) {
for (block_x = 0; block_x + test_config->block_width < handle->width;
block_x += block_step_x) {
sad_plane_bruteforce = av1_motion_search_brute_force_plane(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&best_plane_mv);
av1_plane_to_sphere_erp(block_x + best_plane_mv.x,
block_y + best_plane_mv.y, handle->width,
handle->height, &plane_phi, &plane_theta);
av1_plane_to_sphere_erp(block_x, block_y, handle->width, handle->height,
&block_phi, &block_theta);
start_sphere_mv.phi = plane_phi - block_phi;
start_sphere_mv.theta = plane_theta - block_theta;
sad_plane_diamond = av1_motion_search_diamond_plane(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&best_plane_mv);
sad_erp_bruteforce_p2p = av1_motion_search_brute_force_erp(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&best_sphere_mv);
sad_erp_bruteforce_interp = av1_motion_search_brute_force_erp_interp(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&best_sphere_mv);
sad_erp_diamond_p2p = av1_motion_search_diamond_erp(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&start_sphere_mv, &best_sphere_mv);
sad_erp_diamond_interp = av1_motion_search_diamond_erp_interp(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&start_sphere_mv, &best_sphere_mv);
block_count++;
if (sad_erp_diamond_interp < sad_erp_diamond_p2p) {
block_count_diamond_interp_better++;
}
if (sad_erp_bruteforce_interp < sad_erp_bruteforce_p2p) {
block_count_bruteforce_interp_better++;
}
if (sad_erp_bruteforce_p2p < sad_plane_bruteforce) {
block_count_bruteforce_erp_better++;
}
if (sad_erp_diamond_p2p < sad_plane_diamond) {
block_count_diamond_erp_better++;
}
avg_sad_plane_bruteforce += sad_plane_bruteforce;
avg_sad_plane_diamond += sad_plane_diamond;
avg_sad_erp_diamond_p2p += sad_erp_diamond_p2p;
avg_sad_erp_bruteforce_interp += sad_erp_bruteforce_interp;
avg_sad_erp_bruteforce_p2p += sad_erp_bruteforce_p2p;
avg_sad_erp_diamond_interp += sad_erp_diamond_interp;
}
} // for idx_y
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Processing time: %f second(s)\n ", cpu_time_used);
printf("Total block count: %d\n", block_count);
avg_sad_plane_bruteforce /= block_count;
avg_sad_plane_diamond /= block_count;
avg_sad_erp_diamond_p2p /= block_count;
avg_sad_erp_bruteforce_interp /= block_count;
avg_sad_erp_bruteforce_p2p /= block_count;
avg_sad_erp_diamond_interp /= block_count;
printf("Average plane bruteforce SAD: %d\n", avg_sad_plane_bruteforce);
printf("Average plane diamond SAD: %d\n", avg_sad_plane_diamond);
printf("Pixel to pixel average equirectangle bruteforce SAD: %d\n",
avg_sad_erp_bruteforce_p2p);
printf("Interp average equirectangle bruteforce SAD: %d\n",
avg_sad_erp_bruteforce_interp);
printf("Pixel to pixel average equirectangle diamond SAD: %d\n",
avg_sad_erp_diamond_p2p);
printf("Interp average equirectangle diamond SAD: %d\n",
avg_sad_erp_diamond_interp);
printf("Gain interp vs plane bruteforce: %f%%\n",
100.0 * (avg_sad_plane_bruteforce - avg_sad_erp_bruteforce_interp) /
avg_sad_plane_bruteforce);
printf("Gain interp vs pixel to pixel bruteforce: %f%%\n",
100.0 * (avg_sad_erp_bruteforce_p2p - avg_sad_erp_bruteforce_interp) /
avg_sad_erp_bruteforce_p2p);
printf("Gain interp vs plane diamond: %f%%\n",
100.0 * (avg_sad_plane_bruteforce - avg_sad_erp_diamond_interp) /
avg_sad_plane_bruteforce);
printf(
"%d (%f%%) blocks has less SAD with diamond ERP p2p comparing to "
"burteforce diamond p2p\n",
block_count_diamond_erp_better,
100.0 * block_count_diamond_erp_better / block_count);
printf(
"%d (%f%%) blocks has less SAD with burteforce ERP p2p comparing to "
"burteforce plane p2p\n",
block_count_bruteforce_erp_better,
100.0 * block_count_bruteforce_erp_better / block_count);
printf(
"%d (%f%%) blocks has less SAD with burteforce ERP interpolation "
"comparing to "
"burteforce ERP p2p\n",
block_count_bruteforce_interp_better,
100.0 * block_count_bruteforce_interp_better / block_count);
printf(
"%d (%f%%) blocks has less SAD with diamond ERP interpolation comparing "
"to "
"diamond ERP p2p\n",
block_count_diamond_interp_better,
100.0 * block_count_diamond_interp_better / block_count);
printf("Gain interp vs pixel to pixel diamond: %f%%\n\n",
100.0 * (avg_sad_erp_diamond_p2p - avg_sad_erp_diamond_interp) /
avg_sad_erp_diamond_p2p);
free(cur_pic.img.plane[0]);
free(cur_pic.img.plane[1]);
free(cur_pic.img.plane[2]);
free(ref_pic.img.plane[0]);
free(ref_pic.img.plane[1]);
free(ref_pic.img.plane[2]);
close_file_y4m((handle_t)handle);
}
TEST(SphericalMappingTest, EquiWholeFrameTest) {
TestConfig configs[] = {
{ ARIALCITY960, 60, 65, 1637, 665, 32, 32, 20 },
{ BALBOA960, 180, 185, 514, 187, 32, 32, 20 },
{ BRANCASTLE960, 60, 65, 914, 398, 32, 32, 20 },
{ BROADWAY960, 80, 85, 1518, 570, 32, 32, 20 },
{ GASLAMP960, 210, 215, 1150, 500, 32, 32, 20 },
{ HARBOR960, 1, 5, 50, 490, 32, 32, 20 },
{ KITEFLITE960, 15, 20, 520, 425, 32, 32, 20 },
{ LANDING960, 90, 95, 828, 212, 32, 32, 20 },
{ POLEVAULT960, 30, 35, 328, 800, 32, 32, 20 },
{ TROLLEY960, 90, 95, 1649, 387, 32, 32, 20 },
};
// TestConfig configs[] = {
// { ARIALCITY960, 60, 60, 1637, 665, 32, 32, 20 },
// { BALBOA960, 180, 180, 514, 187, 32, 32, 20 },
// { BRANCASTLE960, 60, 60, 914, 398, 32, 32, 20 },
// { BROADWAY960, 80, 80, 1518, 570, 32, 32, 20 },
// { GASLAMP960, 210, 210, 1150, 500, 32, 32, 20 },
// { HARBOR960, 1, 1, 50, 490, 32, 32, 20 },
// { KITEFLITE960, 15, 15, 520, 425, 32, 32, 20 },
// { LANDING960, 90, 90, 828, 212, 32, 32, 20 },
// { POLEVAULT960, 30, 30, 328, 800, 32, 32, 20 },
// { TROLLEY960, 90, 90, 1649, 387, 32, 32, 20 },
// };
whole_frame_motion_search_test(&configs[0]);
// for (int i = 0; i < 10; i++) {
// whole_frame_motion_search_test(&configs[i]);
// }
}
static void load_frames(y4m_input_t *handle, const TestConfig *test_config,
picture_t *cur_pic, picture_t *ref_pic) {
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
uint8_t temp;
cur_pic->img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic->img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic->img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic->img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic->img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic->img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, ref_pic, test_config->ref_frame_no);
}
static void free_frames(y4m_input_t *handle, picture_t *cur_pic,
picture_t *ref_pic) {
free(cur_pic->img.plane[0]);
free(cur_pic->img.plane[1]);
free(cur_pic->img.plane[2]);
free(ref_pic->img.plane[0]);
free(ref_pic->img.plane[1]);
free(ref_pic->img.plane[2]);
close_file_y4m((handle_t)handle);
}
typedef struct {
int block_count;
int avg_sad_plane_bruteforce;
int avg_sad_plane_diamond;
int avg_sad_erp_bruteforce_p2p;
int avg_sad_erp_bruteforce_interp;
int avg_sad_erp_diamond_interp;
int avg_sad_erp_diamond_p2p;
int cnt_erp_d_interp_beat_erp_d_p2p;
int cnt_erp_d_p2p_beat_erp_d_interp;
int cnt_erp_d_interp_equ_erp_d_p2p;
int cnt_erp_d_interp_beat_plane_d;
int cnt_plane_d_beat_erp_d_interp;
int cnt_erp_d_interp_equ_plane_d;
int cnt_erp_d_interp_beat_plane_br;
int cnt_plane_br_beat_erp_d_interp;
int cnt_erp_d_interp_equ_plane_br;
int cnt_erp_d_p2p_beat_plane_d;
int cnt_plane_d_beat_erp_d_p2p;
int cnt_erp_d_p2p_equ_plane_d;
int cnt_erp_d_p2p_beat_plane_br;
int cnt_plane_br_beat_erp_d_p2p;
int cnt_erp_d_p2p_equ_plane_br;
int cnt_plane_d_equ_plane_br;
} AnalyzeData;
static void init_analyze_data(AnalyzeData *data) {
data->block_count = 0;
data->avg_sad_plane_bruteforce = 0;
data->avg_sad_plane_diamond = 0;
data->avg_sad_erp_bruteforce_p2p = 0;
data->avg_sad_erp_bruteforce_interp = 0;
data->avg_sad_erp_diamond_interp = 0;
data->avg_sad_erp_diamond_p2p = 0;
data->cnt_erp_d_interp_beat_erp_d_p2p = 0;
data->cnt_erp_d_p2p_beat_erp_d_interp = 0;
data->cnt_erp_d_interp_equ_erp_d_p2p = 0;
data->cnt_erp_d_interp_beat_plane_d = 0;
data->cnt_plane_d_beat_erp_d_interp = 0;
data->cnt_erp_d_interp_equ_plane_d = 0;
data->cnt_erp_d_interp_beat_plane_br = 0;
data->cnt_plane_br_beat_erp_d_interp = 0;
data->cnt_erp_d_p2p_beat_plane_d = 0;
data->cnt_plane_d_beat_erp_d_p2p = 0;
data->cnt_erp_d_p2p_beat_plane_br = 0;
data->cnt_plane_br_beat_erp_d_p2p = 0;
data->cnt_plane_d_equ_plane_br = 0;
}
typedef struct {
int sad_plane_bruteforce;
int sad_plane_diamond;
int sad_erp_bruteforce_p2p;
int sad_erp_bruteforce_interp;
int sad_erp_diamond_interp;
int sad_erp_diamond_p2p;
} SearchResult;
typedef enum {
SAD_HIGHER,
SAD_LOWER,
SAD_EQU,
} MarkColor;
// Planed to highlight all the blocks in the frame
// But might be hard to read. Not used.
static void open_block_map(const char *filepath, int width, int height,
FILE *fp) {
int length = 3 * width * height;
char tag[] = { 'B', 'M' };
int header[] = {
0, // File size... update at the end.
0, 0x36, 0x28, width, height, // Image dimensions in pixels
0x180001, 0, 0, 0x002e23, 0x002e23, 0, 0,
};
// Update file size: just the sum of the sizes of the arrays
// we write to disk.
header[0] = sizeof(tag) + sizeof(header) + length;
fp = fopen(filepath, "w+");
fwrite(&tag, sizeof(tag), 1, fp);
fwrite(&header, sizeof(header), 1, fp);
}
static void write_block_map(FILE *fp, uint8_t *r, uint8_t *g, uint8_t *b,
int width, int height) {
int R;
int G;
int B;
for (int j = height - 1; j >= 0; j--) {
for (int i = 0; i < width; i++) {
fwrite(&r[i + j * width], sizeof(*r), 1, fp);
fwrite(&g[i + j * width], sizeof(*r), 1, fp);
fwrite(&b[i + j * width], sizeof(*r), 1, fp);
}
}
}
static void close_block_map(FILE *fp) { fclose(fp); }
// The following 10 functions write detailed search results, including reference
// block coordiantes, pixels, filter kernel, and filter result, into text files.
static void get_blk_coord_plane(int block_x, int block_y, int block_width,
int block_height, int coord_stride,
int frame_width, int frame_height, int *coord_x,
int *coord_y) {
int x_current;
int y_current;
int pos;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
warp_coordinate(frame_width, frame_height, &x_current, &y_current);
pos = idx_x + idx_y * coord_stride;
coord_x[pos] = x_current;
coord_y[pos] = y_current;
}
}
}
static void write_plane_data(const char *data_origin,
const TestConfig *test_config,
const uint8_t *frame, int frame_stride,
int frame_width, int frame_height, int block_x,
int block_y, int block_cnt, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Coordinates:\n", fp);
int coord_x[128 * 128];
int coord_y[128 * 128];
char coord_buf[14];
int pos_coord;
get_blk_coord_plane(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4d, %4d) ", coord_x[pos_coord],
coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame = coord_x[pos_coord] + coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void get_blk_coord_erp(int block_x, int block_y, int block_width,
int block_height, int coord_stride,
int frame_width, int frame_height,
const SphereMV *sphere_mv, int *coord_x,
int *coord_y) {
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double x_ref; // X coordinate in reference frame
double y_ref; // Y coordiante in reference frame
int pos;
PolarVector block_polar;
CartesianVector block_v;
CartesianVector blcok_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += sphere_mv->phi;
block_polar.theta += sphere_mv->theta;
av1_sphere_polar_to_carte(&block_polar, &blcok_v_prime);
av1_carte_vectors_cross_product(&block_v, &blcok_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &blcok_v_prime);
// Avoid floating point precision issues
product = MAX(product, -1.0);
product = MIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * pi;
// v_prime_polar.theta -= pi;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &x_ref, &y_ref);
x_ref = round(x_ref);
x_ref = (int)x_ref == frame_width ? 0 : x_ref;
y_ref = round(y_ref);
y_ref = (int)y_ref == frame_height ? frame_height - 1 : y_ref;
pos = idx_x + idx_y * coord_stride;
coord_x[pos] = (int)x_ref;
coord_y[pos] = (int)y_ref;
}
} // for idx_y
}
static void write_erp_data(const char *data_origin,
const TestConfig *test_config, const uint8_t *frame,
int frame_stride, int frame_width, int frame_height,
int block_x, int block_y, int block_cnt,
SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Coordinates:\n", fp);
int coord_x[128 * 128];
int coord_y[128 * 128];
char coord_buf[14];
int pos_coord;
get_blk_coord_erp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4d, %4d) ", coord_x[pos_coord],
coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame = coord_x[pos_coord] + coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void get_blk_coord_erp_interp(int block_x, int block_y, int block_width,
int block_height, int coord_stride,
int frame_width, int frame_height,
const SphereMV *sphere_mv, double *coord_x,
double *coord_y) {
double x_current; // X coordiante in current frame
double y_current; // Y coordiante in currrent frame
double subpel_x; // X coordinate in reference frame
double subpel_y; // Y coordiante in reference frame
int pos;
PolarVector block_polar;
CartesianVector block_v;
CartesianVector blcok_v_prime;
CartesianVector k; // The axis that the block will rotate along
block_polar.r = 1.0;
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_polar.phi, &block_polar.theta);
block_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&block_polar, &block_v);
block_polar.phi += sphere_mv->phi;
block_polar.theta += sphere_mv->theta;
av1_sphere_polar_to_carte(&block_polar, &blcok_v_prime);
av1_carte_vectors_cross_product(&block_v, &blcok_v_prime, &k);
av1_normalize_carte_vector(&k);
double product = av1_carte_vectors_dot_product(&block_v, &blcok_v_prime);
// Avoid floating point precision issues
product = MAX(product, -1.0);
product = MIN(product, 1.0);
double alpha = acos(product);
CartesianVector v;
CartesianVector v_prime;
PolarVector v_polar;
PolarVector v_prime_polar;
v_polar.r = 1.0;
v_prime_polar.r = 1.0;
double k_dot_v;
for (int idx_y = 0; idx_y < block_height; idx_y++) {
for (int idx_x = 0; idx_x < block_width; idx_x++) {
x_current = idx_x + block_x;
y_current = idx_y + block_y;
av1_plane_to_sphere_erp(x_current, y_current, frame_width, frame_height,
&v_polar.phi, &v_polar.theta);
v_polar.phi += 0.5 * pi;
av1_sphere_polar_to_carte(&v_polar, &v);
k_dot_v = av1_carte_vectors_dot_product(&k, &v);
v_prime.x = k.x * k_dot_v * (1 - cos(alpha)) + v.x * cos(alpha) +
(k.y * v.z - k.z * v.y) * sin(alpha);
v_prime.y = k.y * k_dot_v * (1 - cos(alpha)) + v.y * cos(alpha) +
(k.z * v.x - k.x * v.z) * sin(alpha);
v_prime.z = k.z * k_dot_v * (1 - cos(alpha)) + v.z * cos(alpha) +
(k.x * v.y - k.y * v.x) * sin(alpha);
av1_sphere_carte_to_polar(&v_prime, &v_prime_polar);
v_prime_polar.phi -= 0.5 * pi;
// v_prime_polar.theta -= pi;
av1_sphere_to_plane_erp(v_prime_polar.phi, v_prime_polar.theta,
frame_width, frame_height, &subpel_x, &subpel_y);
// subpel_x = round(subpel_x);
// subpel_x = subpel_x == frame_width ? 0 : subpel_x;
// subpel_y = round(subpel_y);
// subpel_y = subpel_y == frame_height ? frame_height - 1 : subpel_y;
pos = idx_x + idx_y * coord_stride;
coord_x[pos] = subpel_x;
coord_y[pos] = subpel_y;
}
} // for idx_y
}
static void write_erp_interp_data(const char *data_origin,
const TestConfig *test_config,
const uint8_t *frame, int frame_stride,
int frame_width, int frame_height,
int block_x, int block_y, int block_cnt,
SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Sub-pixel coordinates:\n", fp);
double coord_x[128 * 128];
double coord_y[128 * 128];
char coord_buf[24];
int pos_coord;
get_blk_coord_erp_interp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4.4f, %4.4f) ",
coord_x[pos_coord], coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
int int_coord_x[128 * 128];
int int_coord_y[128 * 128];
int kernel_x[128 * 128];
int kernel_y[128 * 128];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
kernel_x[pos_coord] =
cal_kernel_idx(coord_x[pos_coord], &int_coord_x[pos_coord]);
kernel_y[pos_coord] =
cal_kernel_idx(coord_y[pos_coord], &int_coord_y[pos_coord]);
}
}
fputs("\nInteger coordinates (interpolation center):\n", fp);
char int_coord_buf[14];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(int_coord_buf, sizeof(int_coord_buf), "(%4d, %4d) ",
int_coord_x[pos_coord], int_coord_y[pos_coord]);
fputs(int_coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel at interpolation centers:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame =
int_coord_x[pos_coord] + int_coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fputs("\nInterpolation kernels:\n", fp);
char kernel_buf[8];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(kernel_buf, sizeof(kernel_buf), "(%1d, %1d) ",
kernel_x[pos_coord], kernel_y[pos_coord]);
fputs(kernel_buf, fp);
}
fputs("\n", fp);
}
fputs("\nInterpolation results:\n", fp);
uint8_t result;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
result = interp_pixel_plane(frame, frame_stride, frame_width,
frame_height, coord_x[pos_coord],
coord_y[pos_coord], av1_sub_pel_filters_8, 8);
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", result);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void write_erp_interp_data_bilinear(
const char *data_origin, const TestConfig *test_config,
const uint8_t *frame, int frame_stride, int frame_width, int frame_height,
int block_x, int block_y, int block_cnt, SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Sub-pixel coordinates:\n", fp);
double coord_x[128 * 128];
double coord_y[128 * 128];
char coord_buf[24];
int pos_coord;
get_blk_coord_erp_interp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4.4f, %4.4f) ",
coord_x[pos_coord], coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
int int_coord_x[128 * 128];
int int_coord_y[128 * 128];
int kernel_x[128 * 128];
int kernel_y[128 * 128];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
kernel_x[pos_coord] =
cal_kernel_idx(coord_x[pos_coord], &int_coord_x[pos_coord]);
kernel_y[pos_coord] =
cal_kernel_idx(coord_y[pos_coord], &int_coord_y[pos_coord]);
}
}
fputs("\nInteger coordinates (interpolation center):\n", fp);
char int_coord_buf[14];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(int_coord_buf, sizeof(int_coord_buf), "(%4d, %4d) ",
int_coord_x[pos_coord], int_coord_y[pos_coord]);
fputs(int_coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel at interpolation centers:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame =
int_coord_x[pos_coord] + int_coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fputs("\nInterpolation kernels:\n", fp);
char kernel_buf[8];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(kernel_buf, sizeof(kernel_buf), "(%1d, %1d) ",
kernel_x[pos_coord], kernel_y[pos_coord]);
fputs(kernel_buf, fp);
}
fputs("\n", fp);
}
fputs("\nInterpolation results:\n", fp);
uint8_t result;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
result = interp_pixel_plane(frame, frame_stride, frame_width,
frame_height, coord_x[pos_coord],
coord_y[pos_coord], av1_bilinear_filters, 8);
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", result);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void write_erp_interp_data_sub_pel_8(
const char *data_origin, const TestConfig *test_config,
const uint8_t *frame, int frame_stride, int frame_width, int frame_height,
int block_x, int block_y, int block_cnt, SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Sub-pixel coordinates:\n", fp);
double coord_x[128 * 128];
double coord_y[128 * 128];
char coord_buf[24];
int pos_coord;
get_blk_coord_erp_interp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4.4f, %4.4f) ",
coord_x[pos_coord], coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
int int_coord_x[128 * 128];
int int_coord_y[128 * 128];
int kernel_x[128 * 128];
int kernel_y[128 * 128];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
kernel_x[pos_coord] =
cal_kernel_idx(coord_x[pos_coord], &int_coord_x[pos_coord]);
kernel_y[pos_coord] =
cal_kernel_idx(coord_y[pos_coord], &int_coord_y[pos_coord]);
}
}
fputs("\nInteger coordinates (interpolation center):\n", fp);
char int_coord_buf[14];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(int_coord_buf, sizeof(int_coord_buf), "(%4d, %4d) ",
int_coord_x[pos_coord], int_coord_y[pos_coord]);
fputs(int_coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel at interpolation centers:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame =
int_coord_x[pos_coord] + int_coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fputs("\nInterpolation kernels:\n", fp);
char kernel_buf[8];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(kernel_buf, sizeof(kernel_buf), "(%1d, %1d) ",
kernel_x[pos_coord], kernel_y[pos_coord]);
fputs(kernel_buf, fp);
}
fputs("\n", fp);
}
fputs("\nInterpolation results:\n", fp);
uint8_t result;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
result = interp_pixel_plane(frame, frame_stride, frame_width,
frame_height, coord_x[pos_coord],
coord_y[pos_coord], av1_sub_pel_filters_8, 8);
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", result);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void write_erp_interp_data_sub_pel_8sharp(
const char *data_origin, const TestConfig *test_config,
const uint8_t *frame, int frame_stride, int frame_width, int frame_height,
int block_x, int block_y, int block_cnt, SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Sub-pixel coordinates:\n", fp);
double coord_x[128 * 128];
double coord_y[128 * 128];
char coord_buf[24];
int pos_coord;
get_blk_coord_erp_interp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4.4f, %4.4f) ",
coord_x[pos_coord], coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
int int_coord_x[128 * 128];
int int_coord_y[128 * 128];
int kernel_x[128 * 128];
int kernel_y[128 * 128];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
kernel_x[pos_coord] =
cal_kernel_idx(coord_x[pos_coord], &int_coord_x[pos_coord]);
kernel_y[pos_coord] =
cal_kernel_idx(coord_y[pos_coord], &int_coord_y[pos_coord]);
}
}
fputs("\nInteger coordinates (interpolation center):\n", fp);
char int_coord_buf[14];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(int_coord_buf, sizeof(int_coord_buf), "(%4d, %4d) ",
int_coord_x[pos_coord], int_coord_y[pos_coord]);
fputs(int_coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel at interpolation centers:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame =
int_coord_x[pos_coord] + int_coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fputs("\nInterpolation kernels:\n", fp);
char kernel_buf[8];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(kernel_buf, sizeof(kernel_buf), "(%1d, %1d) ",
kernel_x[pos_coord], kernel_y[pos_coord]);
fputs(kernel_buf, fp);
}
fputs("\n", fp);
}
fputs("\nInterpolation results:\n", fp);
uint8_t result;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
result = interp_pixel_plane(
frame, frame_stride, frame_width, frame_height, coord_x[pos_coord],
coord_y[pos_coord], av1_sub_pel_filters_8sharp, 8);
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", result);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
static void write_erp_interp_data_sub_pel_8smooth(
const char *data_origin, const TestConfig *test_config,
const uint8_t *frame, int frame_stride, int frame_width, int frame_height,
int block_x, int block_y, int block_cnt, SphereMV *sphere_mv, int sad) {
char filepath[80];
snprintf(filepath, sizeof(filepath), "%s%04d_%d_%d_%s_%d.txt",
output_filepaths[test_config->filename], block_cnt, block_x, block_y,
data_origin, sad);
FILE *fp = fopen(filepath, "w");
fputs(filepaths[test_config->filename], fp);
fputs("\n\n", fp);
char block_info[80];
snprintf(block_info, sizeof(block_info),
"#%d block at (%d, %d), size %d x %d, SAD: %d\n\n", block_cnt,
block_x, block_y, test_config->block_width,
test_config->block_height, sad);
fputs(block_info, fp);
const int coord_stride = 128;
fputs("Sub-pixel coordinates:\n", fp);
double coord_x[128 * 128];
double coord_y[128 * 128];
char coord_buf[24];
int pos_coord;
get_blk_coord_erp_interp(block_x, block_y, test_config->block_width,
test_config->block_height, coord_stride, frame_width,
frame_height, sphere_mv, coord_x, coord_y);
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(coord_buf, sizeof(coord_buf), "(%4.4f, %4.4f) ",
coord_x[pos_coord], coord_y[pos_coord]);
fputs(coord_buf, fp);
}
fputs("\n", fp);
}
int int_coord_x[128 * 128];
int int_coord_y[128 * 128];
int kernel_x[128 * 128];
int kernel_y[128 * 128];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
kernel_x[pos_coord] =
cal_kernel_idx(coord_x[pos_coord], &int_coord_x[pos_coord]);
kernel_y[pos_coord] =
cal_kernel_idx(coord_y[pos_coord], &int_coord_y[pos_coord]);
}
}
fputs("\nInteger coordinates (interpolation center):\n", fp);
char int_coord_buf[14];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(int_coord_buf, sizeof(int_coord_buf), "(%4d, %4d) ",
int_coord_x[pos_coord], int_coord_y[pos_coord]);
fputs(int_coord_buf, fp);
}
fputs("\n", fp);
}
fputs("\nPixel at interpolation centers:\n", fp);
char pixel_buf[6];
int pos_frame;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
pos_frame =
int_coord_x[pos_coord] + int_coord_y[pos_coord] * frame_stride;
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", frame[pos_frame]);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fputs("\nInterpolation kernels:\n", fp);
char kernel_buf[8];
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
snprintf(kernel_buf, sizeof(kernel_buf), "(%1d, %1d) ",
kernel_x[pos_coord], kernel_y[pos_coord]);
fputs(kernel_buf, fp);
}
fputs("\n", fp);
}
fputs("\nInterpolation results:\n", fp);
uint8_t result;
for (int idx_y = 0; idx_y < test_config->block_height; idx_y++) {
fputs("[", fp);
for (int idx_x = 0; idx_x < test_config->block_width; idx_x++) {
pos_coord = idx_x + idx_y * coord_stride;
result = interp_pixel_plane(
frame, frame_stride, frame_width, frame_height, coord_x[pos_coord],
coord_y[pos_coord], av1_sub_pel_filters_8smooth, 8);
snprintf(pixel_buf, sizeof(pixel_buf), "%3d, ", result);
fputs(pixel_buf, fp);
}
fputs("]\n", fp);
}
fclose(fp);
}
// Do motion searches and write the result into txt files
void do_motion_searches(int block_x, int block_y, int block_width,
int block_height, const uint8_t *cur_frame,
const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height, int search_range,
int block_cnt, const TestConfig *test_config,
SearchResult *result, double *time_used) {
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
double block_phi;
double block_theta;
double plane_phi;
double plane_theta;
mkdir(output_filepaths[test_config->filename], S_IRWXU | S_IRWXG | S_IROTH);
write_plane_data("cur", test_config, cur_frame, frame_stride, frame_width,
frame_height, block_x, block_y, block_cnt, 0);
result->sad_plane_bruteforce = av1_motion_search_brute_force_plane(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &best_plane_mv);
write_plane_data("pl_brt", test_config, ref_frame, frame_stride, frame_width,
frame_height, block_x + best_plane_mv.x,
block_y + best_plane_mv.y, block_cnt,
result->sad_plane_bruteforce);
// Use the result of plane bruteforce as the start of ERP search
av1_plane_to_sphere_erp(block_x + best_plane_mv.x, block_y + best_plane_mv.y,
frame_width, frame_height, &plane_phi, &plane_theta);
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_phi, &block_theta);
start_sphere_mv.phi = plane_phi - block_phi;
start_sphere_mv.theta = plane_theta - block_theta;
result->sad_plane_diamond = av1_motion_search_diamond_plane(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &best_plane_mv);
write_plane_data("pl_dia", test_config, ref_frame, frame_stride, frame_width,
frame_height, block_x + best_plane_mv.x,
block_y + best_plane_mv.y, block_cnt,
result->sad_plane_diamond);
// result->sad_erp_bruteforce_p2p = av1_motion_search_brute_force_erp(
// block_x, block_y, block_width, block_height, cur_frame, ref_frame,
// frame_stride, frame_width, frame_height, search_range,
// &best_sphere_mv);
// result->sad_erp_bruteforce_interp =
// av1_motion_search_brute_force_erp_interp(
// block_x, block_y, block_width, block_height, cur_frame, ref_frame,
// frame_stride, frame_width, frame_height, search_range,
// &best_sphere_mv);
result->sad_erp_diamond_p2p = av1_motion_search_diamond_erp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
write_erp_data("erp_dia", test_config, ref_frame, frame_stride, frame_width,
frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_p2p);
clock_t start, end;
// double cpu_time_used;
start = clock();
result->sad_erp_diamond_interp = av1_motion_search_diamond_erp_interp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
end = clock();
*time_used += ((double)(end - start)) / CLOCKS_PER_SEC;
// printf("Processing time: %f second(s)\n ", time_used);
write_erp_interp_data("erp_dia_interp", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt,
&best_sphere_mv, result->sad_erp_diamond_interp);
}
static void update_analyze_data(const SearchResult *result, AnalyzeData *data) {
if (result->sad_erp_diamond_interp < result->sad_erp_diamond_p2p) {
data->cnt_erp_d_interp_beat_erp_d_p2p++;
} else if (result->sad_erp_diamond_interp > result->sad_erp_diamond_p2p) {
data->cnt_erp_d_p2p_beat_erp_d_interp++;
} else {
data->cnt_erp_d_interp_equ_erp_d_p2p++;
}
if (result->sad_erp_diamond_interp < result->sad_plane_diamond) {
data->cnt_erp_d_interp_beat_plane_d++;
} else if (result->sad_erp_diamond_interp > result->sad_plane_diamond) {
data->cnt_plane_d_beat_erp_d_interp++;
} else {
data->cnt_erp_d_interp_equ_plane_d++;
}
if (result->sad_erp_diamond_interp < result->sad_plane_bruteforce) {
data->cnt_erp_d_interp_beat_plane_br++;
} else if (result->sad_erp_diamond_interp > result->sad_plane_diamond) {
data->cnt_plane_br_beat_erp_d_interp++;
} else {
data->cnt_erp_d_interp_equ_plane_d++;
}
if (result->sad_erp_diamond_p2p < result->sad_plane_diamond) {
data->cnt_erp_d_p2p_beat_plane_d++;
} else if (result->sad_erp_diamond_p2p > result->sad_plane_diamond) {
data->cnt_plane_d_beat_erp_d_p2p++;
} else {
data->cnt_erp_d_p2p_equ_plane_d++;
}
if (result->sad_erp_diamond_p2p < result->sad_plane_bruteforce) {
data->cnt_erp_d_p2p_beat_plane_br++;
} else if (result->sad_erp_diamond_p2p > result->sad_plane_bruteforce) {
data->cnt_plane_br_beat_erp_d_p2p++;
} else {
data->cnt_erp_d_p2p_equ_plane_br++;
}
if (result->sad_plane_diamond == result->sad_plane_bruteforce) {
data->cnt_plane_d_equ_plane_br++;
}
data->avg_sad_plane_bruteforce += result->sad_plane_bruteforce;
data->avg_sad_plane_diamond += result->sad_plane_diamond;
data->avg_sad_erp_diamond_p2p += result->sad_erp_diamond_p2p;
data->avg_sad_erp_bruteforce_interp += result->sad_erp_bruteforce_interp;
data->avg_sad_erp_bruteforce_p2p += result->sad_erp_bruteforce_p2p;
data->avg_sad_erp_diamond_interp += result->sad_erp_diamond_interp;
}
static void update_avg_analyze_data(AnalyzeData *data) {
data->avg_sad_plane_bruteforce /= data->block_count;
data->avg_sad_plane_diamond /= data->block_count;
data->avg_sad_erp_diamond_p2p /= data->block_count;
data->avg_sad_erp_bruteforce_interp /= data->block_count;
data->avg_sad_erp_bruteforce_p2p /= data->block_count;
data->avg_sad_erp_diamond_interp /= data->block_count;
}
static void whole_frame_motion_search_analyze(const TestConfig *test_config) {
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, test_config->ref_frame_no);
uint8_t *cur_frame = cur_pic.img.plane[0];
uint8_t *ref_frame = ref_pic.img.plane[0];
int block_x;
int block_y;
int block_step_x = handle->width / 10;
int block_step_y = handle->height / 10;
AnalyzeData data;
init_analyze_data(&data);
SearchResult search_result;
double erp_dia_interp_time = 0;
// clock_t start, end;
// double cpu_time_used;
printf("File path: %s\n", filepaths[test_config->filename]);
printf("Current frame: %d, reference frame: %d\n", test_config->cur_frame_no,
test_config->ref_frame_no);
printf("Block size: %dx%d, search range: %d\n", test_config->block_width,
test_config->block_height, test_config->search_range);
// start = clock();
for (block_y = 0; block_y + test_config->block_height < handle->height;
block_y += block_step_y) {
for (block_x = 0; block_x + test_config->block_width < handle->width;
block_x += block_step_x) {
do_motion_searches(block_x, block_y, test_config->block_width,
test_config->block_height, cur_frame, ref_frame,
handle->width, handle->width, handle->height,
test_config->search_range, data.block_count + 1,
test_config, &search_result, &erp_dia_interp_time);
data.block_count++;
update_analyze_data(&search_result, &data);
}
} // for idx_y
// end = clock();
// cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Processing time: %f second(s)\n ", erp_dia_interp_time);
printf("Total block count: %d\n", data.block_count);
update_avg_analyze_data(&data);
printf("Average plane bruteforce SAD: %d\n", data.avg_sad_plane_bruteforce);
printf("Average plane diamond SAD: %d\n", data.avg_sad_plane_diamond);
printf("Pixel to pixel average equirectangle bruteforce SAD: %d\n",
data.avg_sad_erp_bruteforce_p2p);
printf("Interp average equirectangle bruteforce SAD: %d\n",
data.avg_sad_erp_bruteforce_interp);
printf("Pixel to pixel average equirectangle diamond SAD: %d\n",
data.avg_sad_erp_diamond_p2p);
printf("Interp average equirectangle diamond SAD: %d\n",
data.avg_sad_erp_diamond_interp);
printf("Gain ERP diamond p2p vs plane bruteforce: %f%%\n",
100.0 *
(data.avg_sad_plane_bruteforce - data.avg_sad_erp_diamond_p2p) /
data.avg_sad_plane_bruteforce);
printf("Gain interp vs plane bruteforce: %f%%\n",
100.0 *
(data.avg_sad_plane_bruteforce - data.avg_sad_erp_diamond_interp) /
data.avg_sad_plane_bruteforce);
printf("Gain interp vs plane diamond: %f%%\n",
100.0 *
(data.avg_sad_plane_diamond - data.avg_sad_erp_diamond_interp) /
data.avg_sad_plane_diamond);
printf("Gain interp vs ERP diamond p2p: %f%%\n",
100.0 *
(data.avg_sad_erp_diamond_p2p - data.avg_sad_erp_diamond_interp) /
data.avg_sad_erp_diamond_p2p);
// printf("Gain interp vs pixel to pixel diamond: %f%%\n",
// 100.0 *
// (data.avg_sad_erp_diamond_p2p -
// data.avg_sad_erp_diamond_interp) /
// data.avg_sad_erp_diamond_p2p);
printf(
"%d (%f%%) blocks has less SAD with burteforce ERP p2p comparing to "
"burteforce plane p2p\n",
data.cnt_erp_d_p2p_beat_plane_br,
100.0 * data.cnt_erp_d_p2p_beat_plane_br / data.block_count);
printf(
"%d (%f%%) blocks has less SAD with diamond ERP p2p comparing to "
"burteforce diamond p2p\n",
data.cnt_erp_d_p2p_beat_plane_d,
100.0 * data.cnt_erp_d_p2p_beat_plane_d / data.block_count);
printf(
"%d (%f%%) blocks has less SAD with burteforce ERP interpolation "
"comparing to "
"plane burteforce p2p\n",
data.cnt_erp_d_interp_beat_plane_br,
100.0 * data.cnt_erp_d_interp_beat_plane_br / data.block_count);
printf(
"%d (%f%%) blocks has less SAD with diamond ERP interpolation "
"comparing "
"to "
"diamond ERP p2p\n\n",
data.cnt_erp_d_interp_beat_erp_d_p2p,
100.0 * data.cnt_erp_d_interp_beat_erp_d_p2p / data.block_count);
free_frames(handle, &cur_pic, &ref_pic);
}
TEST(SphericalMappingTest, EquiWholeFrameAnalyzeTest) {
TestConfig configs[] = {
{ ARIALCITY960, 60, 65, 1637, 665, 32, 32, 20 },
{ BALBOA960, 180, 185, 514, 187, 32, 32, 20 },
{ BRANCASTLE960, 60, 65, 914, 398, 32, 32, 20 },
{ BROADWAY960, 80, 85, 1518, 570, 32, 32, 20 },
{ GASLAMP960, 210, 215, 1150, 500, 32, 32, 20 },
{ HARBOR960, 1, 5, 50, 490, 32, 32, 20 },
{ KITEFLITE960, 15, 20, 520, 425, 32, 32, 20 },
{ LANDING960, 90, 95, 828, 212, 32, 32, 20 },
{ POLEVAULT960, 30, 35, 328, 800, 32, 32, 20 },
{ TROLLEY960, 90, 95, 1649, 387, 32, 32, 20 },
};
// whole_frame_motion_search_analyze(&configs[4]);
for (int i = 0; i < 10; i++) {
whole_frame_motion_search_analyze(&configs[i]);
}
}
void write_bmp_multi_highlight(char *filename, int width, int height,
uint8_t *y, int *highlight1, int *highlight2,
int *highlight3, int *highlight4,
int *highlight5, int *highlight6,
int *highlight7, int *highlight8,
int *highlight9, int block_width,
int block_height, int block_stride) {
int Y;
int length = 3 * width * height;
char tag[] = { 'B', 'M' };
int header[] = {
0, // File size... update at the end.
0, 0x36, 0x28, width, height, // Image dimensions in pixels
0x180001, 0, 0, 0x002e23, 0x002e23, 0, 0,
};
// Update file size: just the sum of the sizes of the arrays
// we write to disk.
header[0] = sizeof(tag) + sizeof(header) + length;
FILE *fp = fopen(filename, "w+");
fwrite(&tag, sizeof(tag), 1, fp);
fwrite(&header, sizeof(header), 1, fp);
uint8_t *lume = (uint8_t *)malloc(width * height * sizeof(*y));
for (int i = 0; i < width * height; i++) {
lume[i] = y[i] * 0.5;
}
for (int j = 0; j < block_height; j++) {
for (int i = 0; i < block_width; i++) {
lume[highlight1[j * block_stride + i]] *= 2;
lume[highlight2[j * block_stride + i]] *= 2;
lume[highlight3[j * block_stride + i]] *= 2;
lume[highlight4[j * block_stride + i]] *= 2;
lume[highlight5[j * block_stride + i]] *= 2;
lume[highlight6[j * block_stride + i]] *= 2;
lume[highlight7[j * block_stride + i]] *= 2;
lume[highlight8[j * block_stride + i]] *= 2;
lume[highlight9[j * block_stride + i]] *= 2;
}
}
for (int j = height - 1; j >= 0; j--) {
for (int i = 0; i < width; i++) {
Y = lume[i + j * width];
fwrite(&Y, sizeof(*y), 1, fp);
fwrite(&Y, sizeof(*y), 1, fp);
fwrite(&Y, sizeof(*y), 1, fp);
}
}
fclose(fp);
free(lume);
}
// Verify blocks get distorted on the plane after moving on sphere
TEST(SphericalMappingTest, EquiDistortionTest) {
char *filename = "360test.y4m";
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filename, (handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
int cur_frame_no = 110;
read_frame_y4m((handle_t)handle, &cur_pic, cur_frame_no);
SphereMV best_sphere_mv;
int block_x = 0;
int block_y = 0;
int block_width = 128;
int block_height = 128;
int cur_block[128 * 128];
int up_block[128 * 128];
int down_block[128 * 128];
int left_block[128 * 128];
int right_block[128 * 128];
int up_left_block[128 * 128];
int down_left_block[128 * 128];
int up_right_block[128 * 128];
int down_right_block[128 * 128];
const int block_stride = 128;
get_pred_block_idx(block_x, block_y, block_width, block_height, -0.25 * pi, 0,
handle->width, handle->width, handle->height, block_stride,
cur_block, up_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, 0.25 * pi, 0,
handle->width, handle->width, handle->height, block_stride,
cur_block, down_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, 0, -0.25 * pi,
handle->width, handle->width, handle->height, block_stride,
cur_block, left_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, 0, 0.25 * pi,
handle->width, handle->width, handle->height, block_stride,
cur_block, right_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, -0.25 * pi,
-0.25 * pi, handle->width, handle->width, handle->height,
block_stride, cur_block, up_left_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, 0.25 * pi,
-0.25 * pi, handle->width, handle->width, handle->height,
block_stride, cur_block, down_left_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, -0.25 * pi,
0.25 * pi, handle->width, handle->width, handle->height,
block_stride, cur_block, up_right_block);
get_pred_block_idx(block_x, block_y, block_width, block_height, 0.25 * pi,
0.25 * pi, handle->width, handle->width, handle->height,
block_stride, cur_block, down_right_block);
write_bmp_multi_highlight(
"blcok_distortion.bmp", handle->width, handle->height,
cur_pic.img.plane[0], cur_block, up_block, down_block, left_block,
right_block, up_left_block, down_left_block, up_right_block,
down_right_block, block_width, block_height, block_stride);
free(cur_pic.img.plane[0]);
free(cur_pic.img.plane[1]);
free(cur_pic.img.plane[2]);
free(ref_pic.img.plane[0]);
free(ref_pic.img.plane[1]);
free(ref_pic.img.plane[2]);
close_file_y4m((handle_t)handle);
}
static void row_blocks_motion_search_test(const TestConfig *test_config) {
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, test_config->ref_frame_no);
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
int block_x;
int block_y;
int block_step_x = handle->width / 5;
int block_step_y = handle->height / 5;
int sad_plane_bruteforce = 0;
int sad_plane_diamond = 0;
int sad_erp_bruteforce_p2p = 0;
int sad_erp_bruteforce_interp = 0;
int sad_erp_diamond_interp = 0;
int sad_erp_diamond_p2p = 0;
int block_count = 0;
clock_t start, end;
double cpu_time_used;
double block_phi;
double block_theta;
double plane_phi;
double plane_theta;
printf("File path: %s\n", filepaths[test_config->filename]);
printf("Current frame: %d, reference frame: %d\n", test_config->cur_frame_no,
test_config->ref_frame_no);
printf("Block size: %dx%d, search range: %d\n", test_config->block_width,
test_config->block_height, test_config->search_range);
printf(
"(block_x, block_y): SAD plane bruteforce, SAD ERP bruteforce(gain), "
"SAD "
"ERP diamond(gain)\n");
for (block_y = 0; block_y + test_config->block_height < handle->height;
block_y += block_step_y) {
for (block_x = 0; block_x + test_config->block_width < handle->width;
block_x += block_step_x) {
sad_plane_bruteforce = 0;
sad_plane_diamond = 0;
sad_erp_bruteforce_p2p = 0;
sad_erp_bruteforce_interp = 0;
sad_erp_diamond_interp = 0;
sad_erp_diamond_p2p = 0;
// start = clock();
sad_plane_bruteforce = av1_motion_search_brute_force_plane(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_pic.img.plane[0], ref_pic.img.plane[0], handle->width,
handle->width, handle->height, test_config->search_range,
&best_plane_mv);
// av1_plane_to_sphere_erp(block_x + best_plane_mv.x,
// block_y + best_plane_mv.y, handle->width,
// handle->height, &plane_phi, &plane_theta);
// av1_plane_to_sphere_erp(block_x, block_y, handle->width,
// handle->height,
// &block_phi, &block_theta);
// start_sphere_mv.phi = plane_phi - block_phi;
// start_sphere_mv.theta = plane_theta - block_theta;
// avg_sad_plane_diamond += av1_motion_search_diamond_plane(
// block_x, block_y, test_config->block_width,
// test_config->block_height, cur_pic.img.plane[0],
// ref_pic.img.plane[0], handle->width, handle->width,
// handle->height, test_config->search_range, &best_plane_mv);
// sad_erp_bruteforce_p2p += av1_motion_search_brute_force_erp(
// block_x, block_y, test_config->block_width,
// test_config->block_height, cur_pic.img.plane[0],
// ref_pic.img.plane[0], handle->width, handle->width,
// handle->height, test_config->search_range, &best_sphere_mv);
// sad_erp_bruteforce_interp =
// av1_motion_search_brute_force_erp_interp(
// block_x, block_y, test_config->block_width,
// test_config->block_height, cur_pic.img.plane[0],
// ref_pic.img.plane[0], handle->width, handle->width,
// handle->height, test_config->search_range, &best_sphere_mv);
// sad_erp_diamond_p2p += av1_motion_search_diamond_erp(
// block_x, block_y, test_config->block_width,
// test_config->block_height, cur_pic.img.plane[0],
// ref_pic.img.plane[0], handle->width, handle->width,
// handle->height, test_config->search_range, &start_sphere_mv,
// &best_sphere_mv);
// sad_erp_diamond_interp = av1_motion_search_diamond_erp_interp(
// block_x, block_y, test_config->block_width,
// test_config->block_height, cur_pic.img.plane[0],
// ref_pic.img.plane[0], handle->width, handle->width,
// handle->height, test_config->search_range, &start_sphere_mv,
// &best_sphere_mv);
// end = clock();
// cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
// printf("Processing time: %f second(s)\n ", cpu_time_used);
printf("(%d, %d): %d, %d(%f%%), %d(%f%%)\t", block_x, block_y,
sad_plane_bruteforce, sad_erp_bruteforce_interp,
100.0 * (sad_plane_bruteforce - sad_erp_bruteforce_interp) /
sad_plane_bruteforce,
sad_erp_diamond_interp,
100.0 * (sad_plane_bruteforce - sad_erp_diamond_interp) /
sad_plane_bruteforce);
block_count++;
}
printf("\n");
}
printf("Total block count: %d\n", block_count);
free(cur_pic.img.plane[0]);
free(cur_pic.img.plane[1]);
free(cur_pic.img.plane[2]);
free(ref_pic.img.plane[0]);
free(ref_pic.img.plane[1]);
free(ref_pic.img.plane[2]);
close_file_y4m((handle_t)handle);
}
TEST(SphericalMappingTest, EquiBlocksTest) {
TestConfig configs[] = {
{ ARIALCITY960, 60, 65, 1637, 665, 32, 32, 20 },
{ BALBOA960, 180, 185, 514, 187, 128, 128, 20 },
{ BRANCASTLE960, 60, 65, 914, 398, 64, 64, 20 },
{ BROADWAY960, 80, 85, 1518, 570, 64, 64, 20 },
{ GASLAMP960, 210, 215, 1150, 500, 64, 64, 20 },
{ HARBOR960, 1, 5, 50, 490, 64, 64, 20 },
{ KITEFLITE960, 15, 20, 520, 425, 32, 32, 20 },
{ LANDING960, 90, 95, 828, 212, 128, 128, 20 },
{ POLEVAULT960, 30, 35, 328, 800, 128, 128, 20 },
{ TROLLEY960, 90, 95, 1649, 387, 128, 128, 20 },
};
for (int i = 0; i < 10; i++) {
row_blocks_motion_search_test(&configs[i]);
printf("\n");
}
}
// The rest code is for data and graphs in the final report
typedef struct {
int avg_sad_plane_bruteforce_p2p;
int avg_sad_plane_bruteforce_interp_bilinear;
int avg_sad_plane_bruteforce_interp_sub_pel_8;
int avg_sad_plane_bruteforce_sub_pel_8sharp;
int avg_sad_plane_bruteforce_sub_pel_8smooth;
int avg_sad_plane_bruteforce_filter_search;
int avg_sad_plane_diamond_p2p;
int avg_sad_plane_diamond_interp_bilinear;
int avg_sad_plane_diamond_interp_sub_pel_8;
int avg_sad_plane_diamond_interp_sub_pel_8sharp;
int avg_sad_plane_diamond_interp_sub_pel_8smooth;
int avg_sad_plane_diamond_interp_filter_search;
// int avg_sad_erp_bruteforce_p2p;
// int avg_sad_erp_bruteforce_interp;
int avg_sad_erp_diamond_p2p;
int avg_sad_erp_diamond_interp_interp_bilinear;
int avg_sad_erp_diamond_interp_interp_sub_pel_8;
int avg_sad_erp_diamond_interp_sub_pel_8sharp;
int avg_sad_erp_diamond_interp_sub_pel_8smooth;
int avg_sad_erp_diamond_interp_filter_search;
int avg_sad_erp_diamond_interp_bilinear_scale;
int avg_sad_erp_diamond_interp_sub_pel_8_scale;
int avg_sad_erp_diamond_interp_sub_pel_8sharp_scale;
int avg_sad_erp_diamond_interp_sub_pel_8smooth_scale;
int avg_sad_erp_diamond_interp_filter_search_scale;
int *sad_plane_bruteforce_p2p;
int *sad_plane_bruteforce_interp_bilinear;
int *sad_plane_bruteforce_interp_sub_pel_8;
int *sad_plane_bruteforce_sub_pel_8sharp;
int *sad_plane_bruteforce_sub_pel_8smooth;
int *sad_plane_bruteforce_filter_search;
int *sad_plane_diamond_p2p;
int *sad_plane_diamond_interp_bilinear;
int *sad_plane_diamond_interp_sub_pel_8;
int *sad_plane_diamond_interp_sub_pel_8sharp;
int *sad_plane_diamond_interp_sub_pel_8smooth;
int *sad_plane_diamond_interp_filter_search;
// int *sad_erp_bruteforce_p2p;
// int *sad_erp_bruteforce_interp;
int *sad_erp_diamond_p2p;
int *sad_erp_diamond_interp_interp_bilinear;
int *sad_erp_diamond_interp_interp_sub_pel_8;
int *sad_erp_diamond_interp_sub_pel_8sharp;
int *sad_erp_diamond_interp_sub_pel_8smooth;
int *sad_erp_diamond_interp_filter_search;
int *sad_erp_diamond_interp_bilinear_scale;
int *sad_erp_diamond_interp_sub_pel_8_scale;
int *sad_erp_diamond_interp_sub_pel_8sharp_scale;
int *sad_erp_diamond_interp_sub_pel_8smooth_scale;
int *sad_erp_diamond_interp_filter_search_scale;
int row_cnt;
int col_cnt;
double time_erp_diamond_interp_interp_bilinear;
double time_erp_diamond_interp_interp_sub_pel_8;
double time_erp_diamond_interp_sub_pel_8sharp;
double time_erp_diamond_interp_sub_pel_8smooth;
double time_erp_diamond_interp_filter_search;
double time_erp_diamond_interp_bilinear_scale;
double time_erp_diamond_interp_sub_pel_8_scale;
double time_erp_diamond_interp_sub_pel_8sharp_scale;
double time_erp_diamond_interp_sub_pel_8smooth_scale;
double time_erp_diamond_interp_filter_search_scale;
} FinalSearchResult;
static void init_final_search_result(FinalSearchResult *result, int row_cnt,
int col_cnt) {
result->row_cnt = row_cnt;
result->col_cnt = col_cnt;
result->avg_sad_plane_bruteforce_p2p = 0;
result->avg_sad_plane_bruteforce_interp_bilinear = 0;
result->avg_sad_plane_bruteforce_interp_sub_pel_8 = 0;
result->avg_sad_plane_bruteforce_sub_pel_8sharp = 0;
result->avg_sad_plane_bruteforce_sub_pel_8smooth = 0;
result->avg_sad_plane_bruteforce_filter_search = 0;
result->avg_sad_plane_diamond_p2p = 0;
result->avg_sad_plane_diamond_interp_bilinear = 0;
result->avg_sad_plane_diamond_interp_sub_pel_8 = 0;
result->avg_sad_plane_diamond_interp_sub_pel_8sharp = 0;
result->avg_sad_plane_diamond_interp_sub_pel_8smooth = 0;
result->avg_sad_plane_diamond_interp_filter_search = 0;
// result->avg_sad_erp_bruteforce_p2p=0;
// result->avg_sad_erp_bruteforce_interp=0;
result->avg_sad_erp_diamond_p2p = 0;
result->avg_sad_erp_diamond_interp_interp_bilinear = 0;
result->avg_sad_erp_diamond_interp_interp_sub_pel_8 = 0;
result->avg_sad_erp_diamond_interp_sub_pel_8sharp = 0;
result->avg_sad_erp_diamond_interp_sub_pel_8smooth = 0;
result->avg_sad_erp_diamond_interp_filter_search = 0;
result->avg_sad_erp_diamond_interp_bilinear_scale = 0;
result->avg_sad_erp_diamond_interp_sub_pel_8_scale = 0;
result->avg_sad_erp_diamond_interp_sub_pel_8sharp_scale = 0;
result->avg_sad_erp_diamond_interp_sub_pel_8smooth_scale = 0;
result->avg_sad_erp_diamond_interp_filter_search_scale = 0;
result->time_erp_diamond_interp_interp_bilinear = 0;
result->time_erp_diamond_interp_interp_sub_pel_8 = 0;
result->time_erp_diamond_interp_sub_pel_8sharp = 0;
result->time_erp_diamond_interp_sub_pel_8smooth = 0;
result->time_erp_diamond_interp_filter_search = 0;
result->time_erp_diamond_interp_bilinear_scale = 0;
result->time_erp_diamond_interp_sub_pel_8_scale = 0;
result->time_erp_diamond_interp_sub_pel_8sharp_scale = 0;
result->time_erp_diamond_interp_sub_pel_8smooth_scale = 0;
result->time_erp_diamond_interp_filter_search_scale = 0;
result->sad_plane_bruteforce_p2p =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_bruteforce_interp_bilinear =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_bruteforce_interp_sub_pel_8 =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_bruteforce_sub_pel_8sharp =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_bruteforce_sub_pel_8smooth =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_bruteforce_filter_search =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_p2p =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_interp_bilinear =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_interp_sub_pel_8 =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_interp_sub_pel_8sharp =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_interp_sub_pel_8smooth =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_plane_diamond_interp_filter_search =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
// result->sad_erp_bruteforce_p2p =
// (int *)malloc(row_cnt * col_cnt * sizeof(int));
// result->sad_erp_bruteforce_interp =
// (int *)malloc(row_cnt * col_cnt * sizeof(int));
result->sad_erp_diamond_p2p =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_interp_bilinear =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_interp_sub_pel_8 =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_sub_pel_8sharp =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_sub_pel_8smooth =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_filter_search =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_bilinear_scale =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_sub_pel_8_scale =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_sub_pel_8sharp_scale =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_sub_pel_8smooth_scale =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
result->sad_erp_diamond_interp_filter_search_scale =
(int *)malloc(row_cnt * col_cnt * sizeof(row_cnt));
}
static void cal_avg_sad(FinalSearchResult *result) {
int blk_cnt = result->row_cnt * result->col_cnt;
for (int i = 0; i < blk_cnt; i++) {
result->avg_sad_plane_bruteforce_p2p += result->sad_plane_bruteforce_p2p[i];
result->avg_sad_plane_bruteforce_interp_bilinear +=
result->sad_plane_bruteforce_interp_bilinear[i];
result->avg_sad_plane_bruteforce_interp_sub_pel_8 +=
result->sad_plane_bruteforce_interp_sub_pel_8[i];
result->avg_sad_plane_bruteforce_sub_pel_8sharp +=
result->sad_plane_bruteforce_sub_pel_8sharp[i];
result->avg_sad_plane_bruteforce_sub_pel_8smooth +=
result->sad_plane_bruteforce_sub_pel_8smooth[i];
result->avg_sad_plane_bruteforce_filter_search +=
result->sad_plane_bruteforce_filter_search[i];
result->avg_sad_plane_diamond_p2p += result->sad_plane_diamond_p2p[i];
result->avg_sad_plane_diamond_interp_bilinear +=
result->sad_plane_diamond_interp_bilinear[i];
result->avg_sad_plane_diamond_interp_sub_pel_8 +=
result->sad_plane_diamond_interp_sub_pel_8[i];
result->avg_sad_plane_diamond_interp_sub_pel_8sharp +=
result->sad_plane_diamond_interp_sub_pel_8sharp[i];
result->avg_sad_plane_diamond_interp_sub_pel_8smooth +=
result->sad_plane_diamond_interp_sub_pel_8smooth[i];
result->avg_sad_plane_diamond_interp_filter_search +=
result->sad_plane_diamond_interp_filter_search[i];
result->avg_sad_erp_diamond_p2p += result->sad_erp_diamond_p2p[i];
result->avg_sad_erp_diamond_interp_interp_bilinear +=
result->sad_erp_diamond_interp_interp_bilinear[i];
result->avg_sad_erp_diamond_interp_interp_sub_pel_8 +=
result->sad_erp_diamond_interp_interp_sub_pel_8[i];
result->avg_sad_erp_diamond_interp_sub_pel_8sharp +=
result->sad_erp_diamond_interp_sub_pel_8sharp[i];
result->avg_sad_erp_diamond_interp_sub_pel_8smooth +=
result->sad_erp_diamond_interp_sub_pel_8smooth[i];
result->avg_sad_erp_diamond_interp_filter_search +=
result->sad_erp_diamond_interp_filter_search[i];
result->avg_sad_erp_diamond_interp_bilinear_scale +=
result->sad_erp_diamond_interp_bilinear_scale[i];
result->avg_sad_erp_diamond_interp_sub_pel_8_scale +=
result->sad_erp_diamond_interp_sub_pel_8_scale[i];
result->avg_sad_erp_diamond_interp_sub_pel_8sharp_scale +=
result->sad_erp_diamond_interp_sub_pel_8sharp_scale[i];
result->avg_sad_erp_diamond_interp_sub_pel_8smooth_scale +=
result->sad_erp_diamond_interp_sub_pel_8smooth_scale[i];
result->avg_sad_erp_diamond_interp_filter_search_scale +=
result->sad_erp_diamond_interp_filter_search_scale[i];
} // for
result->avg_sad_plane_bruteforce_p2p /= blk_cnt;
result->avg_sad_plane_bruteforce_interp_bilinear /= blk_cnt;
result->avg_sad_plane_bruteforce_interp_sub_pel_8 /= blk_cnt;
result->avg_sad_plane_bruteforce_sub_pel_8sharp /= blk_cnt;
result->avg_sad_plane_bruteforce_sub_pel_8smooth /= blk_cnt;
result->avg_sad_plane_bruteforce_filter_search /= blk_cnt;
result->avg_sad_plane_diamond_p2p /= blk_cnt;
result->avg_sad_plane_diamond_interp_bilinear /= blk_cnt;
result->avg_sad_plane_diamond_interp_sub_pel_8 /= blk_cnt;
result->avg_sad_plane_diamond_interp_sub_pel_8sharp /= blk_cnt;
result->avg_sad_plane_diamond_interp_sub_pel_8smooth /= blk_cnt;
result->avg_sad_plane_diamond_interp_filter_search /= blk_cnt;
result->avg_sad_erp_diamond_p2p /= blk_cnt;
result->avg_sad_erp_diamond_interp_interp_bilinear /= blk_cnt;
result->avg_sad_erp_diamond_interp_interp_sub_pel_8 /= blk_cnt;
result->avg_sad_erp_diamond_interp_sub_pel_8sharp /= blk_cnt;
result->avg_sad_erp_diamond_interp_sub_pel_8smooth /= blk_cnt;
result->avg_sad_erp_diamond_interp_filter_search /= blk_cnt;
result->avg_sad_erp_diamond_interp_bilinear_scale /= blk_cnt;
result->avg_sad_erp_diamond_interp_sub_pel_8_scale /= blk_cnt;
result->avg_sad_erp_diamond_interp_sub_pel_8sharp_scale /= blk_cnt;
result->avg_sad_erp_diamond_interp_sub_pel_8smooth_scale /= blk_cnt;
result->avg_sad_erp_diamond_interp_filter_search_scale /= blk_cnt;
}
static char *final_results_filepaths[] = {
"./final_analyze/360test/", "./final_analyze/AerialCity/",
"./final_analyze/Balboa/", "./final_analyze/BranCastle/",
"./final_analyze/Broadway/", "./final_analyze/Gaslamp/",
"./final_analyze/Harbor/", "./final_analyze/KiteFlite/",
"./final_analyze/Landing/", "./final_analyze/PoleVault/",
"./final_analyze/Trolley/",
};
static void write_sad_map(FILE *fp, char *label, int *map, int row_cnt,
int col_cnt) {
fprintf(fp, "# %s #\n\n", label);
for (int i = 0; i < row_cnt; i++) {
for (int j = 0; j < col_cnt; j++) {
fprintf(fp, "%d", map[j + i * col_cnt]);
if (j < col_cnt - 1) {
fprintf(fp, ", ");
}
} // for j
fprintf(fp, "\n");
} // for i
fprintf(fp, "\n");
}
static void write_final_search_result(const TestConfig *test_config,
const FinalSearchResult *result) {
mkdir(final_results_filepaths[test_config->filename],
S_IRWXU | S_IRWXG | S_IROTH);
char filepath[80];
snprintf(filepath, sizeof(filepath), "%sresults.csv",
final_results_filepaths[test_config->filename]);
FILE *fp = fopen(filepath, "w");
fprintf(fp, "%s\n", filepaths[test_config->filename]);
fprintf(fp,
"Block at (%d, %d), size %d x %d, current frame: %d, reference "
"frame: %d\n\n",
test_config->block_x, test_config->block_y, test_config->block_width,
test_config->block_height, test_config->cur_frame_no,
test_config->ref_frame_no);
fprintf(fp, "************************\n");
fprintf(fp, "* Average SADs: *\n");
fprintf(fp, "************************\n\n");
fprintf(
fp,
"Plane Bruteforce P2P, Plane Bruteforce Bilinear, Plane Bruteforce 8 "
"Tap, Plane Bruteforce 8 Tap Sharp, Plane Bruteforce 8 Tap Smooth, "
"Plane Bruteforce Filter Search, "
"Plane Diamond P2P, Plane Diamond Bilinear, Plane Diamond 8 "
"Tap, Plane Diamond 8 Tap Sharp, Plane Diamond 8 Tap Smooth, "
"Plane Diamond Filter Search, "
"ERP Diamond P2P, ERP Diamond Bilinear, ERP Diamond 8 "
"Tap, ERP Diamond 8 Tap Sharp, ERP Diamond 8 Tap Smooth, "
"ERP Diamond Filter Search, "
"ERP Scaled Diamond Bilinear, ERP Scaled Diamond 8 "
"Tap, ERP Scaled Diamond 8 Tap Sharp, ERP Scaled Diamond 8 Tap Smooth, "
"ERP Scaled Diamond Filter Search\n");
fprintf(fp,
"%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, "
"%d, %d, %d, %d, %d, %d",
result->avg_sad_plane_bruteforce_p2p,
result->avg_sad_plane_bruteforce_interp_bilinear,
result->avg_sad_plane_bruteforce_interp_sub_pel_8,
result->avg_sad_plane_bruteforce_sub_pel_8sharp,
result->avg_sad_plane_bruteforce_sub_pel_8smooth,
result->avg_sad_plane_bruteforce_filter_search,
result->avg_sad_plane_diamond_p2p,
result->avg_sad_plane_diamond_interp_bilinear,
result->avg_sad_plane_diamond_interp_sub_pel_8,
result->avg_sad_plane_diamond_interp_sub_pel_8sharp,
result->avg_sad_plane_diamond_interp_sub_pel_8smooth,
result->avg_sad_plane_diamond_interp_filter_search,
result->avg_sad_erp_diamond_p2p,
result->avg_sad_erp_diamond_interp_interp_bilinear,
result->avg_sad_erp_diamond_interp_interp_sub_pel_8,
result->avg_sad_erp_diamond_interp_sub_pel_8sharp,
result->avg_sad_erp_diamond_interp_sub_pel_8smooth,
result->avg_sad_erp_diamond_interp_filter_search,
result->avg_sad_erp_diamond_interp_bilinear_scale,
result->avg_sad_erp_diamond_interp_sub_pel_8_scale,
result->avg_sad_erp_diamond_interp_sub_pel_8sharp_scale,
result->avg_sad_erp_diamond_interp_sub_pel_8smooth_scale,
result->avg_sad_erp_diamond_interp_filter_search_scale);
fprintf(fp, "\n\n");
fprintf(fp, "************************\n");
fprintf(fp, "* Process time: *\n");
fprintf(fp, "************************\n\n");
fprintf(
fp,
"ERP Diamond Bilinear, ERP Diamond 8 "
"Tap, ERP Diamond 8 Tap Sharp, ERP Diamond 8 Tap Smooth, "
"ERP Diamond Filter Search, "
"ERP Scaled Diamond Bilinear, ERP Scaled Diamond 8 "
"Tap, ERP Scaled Diamond 8 Tap Sharp, ERP Scaled Diamond 8 Tap Smooth, "
"ERP Scaled Diamond Filter Search\n");
fprintf(fp, "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f",
result->time_erp_diamond_interp_interp_bilinear,
result->time_erp_diamond_interp_interp_sub_pel_8,
result->time_erp_diamond_interp_sub_pel_8sharp,
result->time_erp_diamond_interp_sub_pel_8smooth,
result->time_erp_diamond_interp_filter_search,
result->time_erp_diamond_interp_bilinear_scale,
result->time_erp_diamond_interp_sub_pel_8_scale,
result->time_erp_diamond_interp_sub_pel_8sharp_scale,
result->time_erp_diamond_interp_sub_pel_8smooth_scale,
result->time_erp_diamond_interp_filter_search_scale);
fprintf(fp, "\n\n");
fprintf(fp, "########################\n");
fprintf(fp, "# SAD map: #\n");
fprintf(fp, "########################\n\n");
write_sad_map(fp, "Plane Bruteforce P2P", result->sad_plane_bruteforce_p2p,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "Plane Bruteforce Bilinear",
result->sad_plane_bruteforce_interp_bilinear, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Bruteforce 8 Tap",
result->sad_plane_bruteforce_interp_sub_pel_8, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Bruteforce 8 Tap Sharp",
result->sad_plane_bruteforce_sub_pel_8sharp, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Bruteforce 8 Tap Smooth",
result->sad_plane_bruteforce_sub_pel_8smooth, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Bruteforce Filter Search",
result->sad_plane_bruteforce_filter_search, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Diamond P2P", result->sad_plane_diamond_p2p,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "Plane Diamond Bilinear",
result->sad_plane_diamond_interp_bilinear, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Diamond 8 Tap",
result->sad_plane_diamond_interp_sub_pel_8, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "Plane Diamond 8 Tap Sharp",
result->sad_plane_diamond_interp_sub_pel_8sharp,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "Plane Diamond 8 Tap Smooth",
result->sad_plane_diamond_interp_sub_pel_8smooth,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "Plane Diamond Filter Search",
result->sad_plane_diamond_interp_filter_search, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Diamond P2P", result->sad_erp_diamond_p2p,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "ERP Diamond Bilinear",
result->sad_erp_diamond_interp_interp_bilinear, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Diamond 8 Tap",
result->sad_erp_diamond_interp_interp_sub_pel_8,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "ERP Diamond 8 Tap Sharp",
result->sad_erp_diamond_interp_sub_pel_8sharp, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Diamond 8 Tap Smooth",
result->sad_erp_diamond_interp_sub_pel_8smooth, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Diamond Filter Search",
result->sad_erp_diamond_interp_filter_search, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Scaled Diamond Bilinear",
result->sad_erp_diamond_interp_bilinear_scale, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Scaled Diamond 8 Tap",
result->sad_erp_diamond_interp_sub_pel_8_scale, result->row_cnt,
result->col_cnt);
write_sad_map(fp, "ERP Scaled Diamond 8 Tap Sharp",
result->sad_erp_diamond_interp_sub_pel_8sharp_scale,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "ERP Scaled Diamond 8 Tap Smooth",
result->sad_erp_diamond_interp_sub_pel_8smooth_scale,
result->row_cnt, result->col_cnt);
write_sad_map(fp, "ERP Scaled Diamond Filter Search",
result->sad_erp_diamond_interp_filter_search_scale,
result->row_cnt, result->col_cnt);
fclose(fp);
}
static void free_final_search_result(FinalSearchResult *result) {
free(result->sad_plane_bruteforce_p2p);
free(result->sad_plane_bruteforce_interp_bilinear);
free(result->sad_plane_bruteforce_interp_sub_pel_8);
free(result->sad_plane_bruteforce_sub_pel_8sharp);
free(result->sad_plane_bruteforce_sub_pel_8smooth);
free(result->sad_plane_bruteforce_filter_search);
free(result->sad_plane_diamond_p2p);
free(result->sad_plane_diamond_interp_bilinear);
free(result->sad_plane_diamond_interp_sub_pel_8);
free(result->sad_plane_diamond_interp_sub_pel_8sharp);
free(result->sad_plane_diamond_interp_sub_pel_8smooth);
free(result->sad_plane_diamond_interp_filter_search);
// free(result->sad_erp_bruteforce_p2p);
// free(result->sad_erp_bruteforce_interp);
free(result->sad_erp_diamond_p2p);
free(result->sad_erp_diamond_interp_interp_bilinear);
free(result->sad_erp_diamond_interp_interp_sub_pel_8);
free(result->sad_erp_diamond_interp_sub_pel_8sharp);
free(result->sad_erp_diamond_interp_sub_pel_8smooth);
free(result->sad_erp_diamond_interp_filter_search);
free(result->sad_erp_diamond_interp_bilinear_scale);
free(result->sad_erp_diamond_interp_sub_pel_8_scale);
free(result->sad_erp_diamond_interp_sub_pel_8sharp_scale);
free(result->sad_erp_diamond_interp_sub_pel_8smooth_scale);
free(result->sad_erp_diamond_interp_filter_search_scale);
}
void do_final_motion_searches(int block_x, int block_y, int block_width,
int block_height, const uint8_t *cur_frame,
const uint8_t *ref_frame, int frame_stride,
int frame_width, int frame_height,
int search_range, int block_cnt,
const TestConfig *test_config,
FinalSearchResult *result) {
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
PlaneMV start_plane_mv;
double block_phi;
double block_theta;
double plane_phi;
double plane_theta;
clock_t start, end;
write_plane_data("cur", test_config, cur_frame, frame_stride, frame_width,
frame_height, block_x, block_y, block_cnt, 0);
result->sad_plane_bruteforce_p2p[block_cnt] =
av1_motion_search_brute_force_plane(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
write_plane_data("pl_brt", test_config, ref_frame, frame_stride, frame_width,
frame_height, block_x + best_plane_mv.x,
block_y + best_plane_mv.y, block_cnt,
result->sad_plane_bruteforce_p2p[block_cnt]);
// Use the result of plane bruteforce as the start of ERP search
start_plane_mv.x = best_plane_mv.x;
start_plane_mv.y = best_plane_mv.y;
av1_plane_to_sphere_erp(block_x + best_plane_mv.x, block_y + best_plane_mv.y,
frame_width, frame_height, &plane_phi, &plane_theta);
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_phi, &block_theta);
start_sphere_mv.phi = plane_phi - block_phi;
start_sphere_mv.theta = plane_theta - block_theta;
result->sad_plane_bruteforce_interp_bilinear[block_cnt] =
av1_motion_search_brute_force_plane_interp_bilinear(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_plane_mv, &best_plane_mv);
result->sad_plane_bruteforce_interp_sub_pel_8[block_cnt] =
av1_motion_search_brute_force_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_plane_mv, &best_plane_mv);
result->sad_plane_bruteforce_sub_pel_8sharp[block_cnt] =
av1_motion_search_brute_force_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_plane_mv, &best_plane_mv);
result->sad_plane_bruteforce_sub_pel_8smooth[block_cnt] =
av1_motion_search_brute_force_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_plane_mv, &best_plane_mv);
result->sad_plane_bruteforce_filter_search[block_cnt] =
av1_motion_search_brute_force_plane_interp_filter_search(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_plane_mv, &best_plane_mv);
result->sad_plane_diamond_p2p[block_cnt] = av1_motion_search_diamond_plane(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &best_plane_mv);
result->sad_plane_diamond_interp_bilinear[block_cnt] =
av1_motion_search_diamond_plane_interp_bilinear(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
result->sad_plane_diamond_interp_sub_pel_8[block_cnt] =
av1_motion_search_diamond_plane_interp_sub_pel_8(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
result->sad_plane_diamond_interp_sub_pel_8sharp[block_cnt] =
av1_motion_search_diamond_plane_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
result->sad_plane_diamond_interp_sub_pel_8smooth[block_cnt] =
av1_motion_search_diamond_plane_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
result->sad_plane_diamond_interp_filter_search[block_cnt] =
av1_motion_search_diamond_plane_interp_filter_search(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&best_plane_mv);
result->sad_erp_diamond_p2p[block_cnt] = av1_motion_search_diamond_erp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
write_erp_data("erp_dia", test_config, ref_frame, frame_stride, frame_width,
frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_p2p[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_interp_bilinear[block_cnt] =
av1_motion_search_diamond_erp_interp_bilinear(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_interp_bilinear +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_bilinear(
"erp_dia_interp_bilinear", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_interp_bilinear[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_interp_sub_pel_8[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_interp_sub_pel_8 +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8(
"erp_dia_interp_sub_pel_8", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_interp_sub_pel_8[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_sub_pel_8sharp[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8sharp(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_sub_pel_8sharp +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8sharp(
"erp_dia_interp_sub_pel_8sharp", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_sub_pel_8sharp[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_sub_pel_8smooth[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8smooth(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_sub_pel_8smooth +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8smooth(
"erp_dia_interp_sub_pel_8smooth", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_sub_pel_8smooth[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_filter_search[block_cnt] =
av1_motion_search_diamond_erp_interp_filter_search(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_filter_search +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data(
"erp_dia_interp_filter_search", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_filter_search[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_bilinear_scale[block_cnt] =
av1_motion_search_diamond_erp_interp_bilinear_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_bilinear_scale +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_bilinear(
"erp_dia_interp_bilinear_scale", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_bilinear_scale[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_sub_pel_8_scale[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_sub_pel_8_scale +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8(
"erp_dia_interp_sub_pel_8_scale", test_config, ref_frame, frame_stride,
frame_width, frame_height, block_x, block_y, block_cnt, &best_sphere_mv,
result->sad_erp_diamond_interp_sub_pel_8_scale[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_sub_pel_8sharp_scale[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8sharp_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_sub_pel_8sharp_scale +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8sharp(
"erp_dia_interp_sub_pel_8sharp_scale", test_config, ref_frame,
frame_stride, frame_width, frame_height, block_x, block_y, block_cnt,
&best_sphere_mv,
result->sad_erp_diamond_interp_sub_pel_8sharp_scale[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_sub_pel_8smooth_scale[block_cnt] =
av1_motion_search_diamond_erp_interp_sub_pel_8smooth_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_sub_pel_8smooth_scale +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data_sub_pel_8smooth(
"erp_dia_interp_sub_pel_8smooth_scale", test_config, ref_frame,
frame_stride, frame_width, frame_height, block_x, block_y, block_cnt,
&best_sphere_mv,
result->sad_erp_diamond_interp_sub_pel_8smooth_scale[block_cnt]);
start = clock();
result->sad_erp_diamond_interp_filter_search_scale[block_cnt] =
av1_motion_search_diamond_erp_interp_filter_search_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range,
&start_sphere_mv, &best_sphere_mv);
end = clock();
result->time_erp_diamond_interp_filter_search_scale +=
((double)(end - start)) / CLOCKS_PER_SEC;
write_erp_interp_data(
"erp_dia_interp_filter_search_scale", test_config, ref_frame,
frame_stride, frame_width, frame_height, block_x, block_y, block_cnt,
&best_sphere_mv,
result->sad_erp_diamond_interp_filter_search_scale[block_cnt]);
}
static void whole_frame_final_analyze(const TestConfig *test_config) {
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[test_config->filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, test_config->cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, test_config->ref_frame_no);
uint8_t *cur_frame = cur_pic.img.plane[0];
uint8_t *ref_frame = ref_pic.img.plane[0];
int block_x;
int block_y;
int row_cnt = 10;
int col_cnt = 10;
int block_step_x = handle->width / col_cnt;
int block_step_y = handle->height / row_cnt;
// AnalyzeData data;
// init_analyze_data(&data);
FinalSearchResult search_result;
init_final_search_result(&search_result, row_cnt, col_cnt);
int block_count = 0;
mkdir(output_filepaths[test_config->filename], S_IRWXU | S_IRWXG | S_IROTH);
// clock_t start, end;
// double cpu_time_used;
printf("File path: %s\n", filepaths[test_config->filename]);
printf("Current frame: %d, reference frame: %d\n", test_config->cur_frame_no,
test_config->ref_frame_no);
printf("Block size: %dx%d, search range: %d\n", test_config->block_width,
test_config->block_height, test_config->search_range);
for (block_y = 0; block_y + test_config->block_height < handle->height;
block_y += block_step_y) {
for (block_x = 0; block_x + test_config->block_width < handle->width;
block_x += block_step_x) {
do_final_motion_searches(
block_x, block_y, test_config->block_width, test_config->block_height,
cur_frame, ref_frame, handle->width, handle->width, handle->height,
test_config->search_range, block_count, test_config, &search_result);
block_count++;
printf("%d\n", block_count);
}
} // for idx_y
cal_avg_sad(&search_result);
write_final_search_result(test_config, &search_result);
free_frames(handle, &cur_pic, &ref_pic);
free_final_search_result(&search_result);
}
TEST(SphericalMappingTest, FinalTest) {
TestConfig configs[] = {
{ ARIALCITY960, 60, 65, 1637, 665, 32, 32, 20 },
{ BALBOA960, 180, 185, 514, 187, 32, 32, 20 },
{ BRANCASTLE960, 60, 65, 914, 398, 32, 32, 20 },
{ BROADWAY960, 80, 85, 1518, 570, 32, 32, 20 },
{ GASLAMP960, 210, 215, 1150, 500, 32, 32, 20 },
{ HARBOR960, 1, 5, 50, 490, 32, 32, 20 },
{ KITEFLITE960, 15, 20, 520, 425, 32, 32, 20 },
{ LANDING960, 90, 95, 828, 212, 32, 32, 20 },
{ POLEVAULT960, 30, 35, 328, 800, 32, 32, 20 },
{ TROLLEY960, 90, 95, 1649, 387, 32, 32, 20 },
};
// whole_frame_final_analyze(&configs[4]);
// for (int i = 0; i < 10; i++) {
// whole_frame_final_analyze(&configs[i]);
// }
y4m_input_t *handle = NULL;
config_t config;
ASSERT_EQ(0, open_file_y4m(filepaths[configs[4].filename],
(handle_t *)(&handle), &config));
picture_t cur_pic;
picture_t ref_pic;
uint8_t temp;
cur_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
cur_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
cur_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[0] =
(uint8_t *)malloc(handle->width * handle->height * sizeof(temp));
ref_pic.img.plane[1] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
ref_pic.img.plane[2] =
(uint8_t *)malloc(handle->width * handle->height / 4 * sizeof(temp));
read_frame_y4m((handle_t)handle, &cur_pic, configs[4].cur_frame_no);
read_frame_y4m((handle_t)handle, &ref_pic, configs[4].ref_frame_no);
uint8_t *cur_frame = cur_pic.img.plane[0];
uint8_t *ref_frame = ref_pic.img.plane[0];
int pred_block[128 * 128];
int cur_block[128 * 128];
int block_stride = 128;
int block_x = 1344;
int block_y = 576;
int block_width = configs[4].block_width;
int block_height = configs[4].block_height;
int frame_stride = handle->width;
int frame_width = handle->width;
int frame_height = handle->height;
int search_range = configs[4].search_range;
SphereMV start_sphere_mv;
start_sphere_mv.phi = 0;
start_sphere_mv.theta = 0;
SphereMV best_sphere_mv;
PlaneMV best_plane_mv;
PlaneMV start_plane_mv;
double block_phi;
double block_theta;
double plane_phi;
double plane_theta;
av1_motion_search_brute_force_plane(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &best_plane_mv);
start_plane_mv.x = best_plane_mv.x;
start_plane_mv.y = best_plane_mv.y;
av1_plane_to_sphere_erp(block_x + best_plane_mv.x, block_y + best_plane_mv.y,
frame_width, frame_height, &plane_phi, &plane_theta);
av1_plane_to_sphere_erp(block_x, block_y, frame_width, frame_height,
&block_phi, &block_theta);
start_sphere_mv.phi = plane_phi - block_phi;
start_sphere_mv.theta = plane_theta - block_theta;
av1_motion_search_diamond_erp(block_x, block_y, block_width, block_height,
cur_frame, ref_frame, frame_stride, frame_width,
frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
get_pred_block_idx(block_x, block_y, block_width, block_height,
best_sphere_mv.phi, best_sphere_mv.theta, frame_stride,
frame_width, frame_height, block_stride, cur_block,
pred_block);
write_bmp("car_cur.bmp", frame_width, frame_height, cur_pic.img.plane[0],
cur_block, block_width, block_height, block_stride);
write_bmp("car_ref_dia_p2p.bmp", frame_width, frame_height,
ref_pic.img.plane[0], pred_block, block_width, block_height,
block_stride);
av1_motion_search_diamond_erp_interp_sub_pel_8(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
get_pred_block_idx(block_x, block_y, block_width, block_height,
best_sphere_mv.phi, best_sphere_mv.theta, frame_stride,
frame_width, frame_height, block_stride, cur_block,
pred_block);
write_bmp("car_ref_dia_subpl.bmp", frame_width, frame_height,
ref_pic.img.plane[0], pred_block, block_width, block_height,
block_stride);
av1_motion_search_diamond_erp_interp_sub_pel_8_scale(
block_x, block_y, block_width, block_height, cur_frame, ref_frame,
frame_stride, frame_width, frame_height, search_range, &start_sphere_mv,
&best_sphere_mv);
get_pred_block_idx(block_x, block_y, block_width, block_height,
best_sphere_mv.phi, best_sphere_mv.theta, frame_stride,
frame_width, frame_height, block_stride, cur_block,
pred_block);
write_bmp("car_ref_dia_subpl_scale.bmp", frame_width, frame_height,
ref_pic.img.plane[0], pred_block, block_width, block_height,
block_stride);
free_frames(handle, &cur_pic, &ref_pic);
}
} // namespace