Picture and reference may have different sizes

This commit is contained in:
Laurent Fasnacht 2014-04-24 08:30:09 +02:00
parent af9a1c0fbb
commit 2e7d958af3

View file

@ -27,6 +27,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <assert.h>
#include "sao.h" #include "sao.h"
@ -713,7 +714,7 @@ static unsigned sad_nxn_16bit(pixel *block1, pixel *block2, unsigned n)
* \returns Sum of Absolute Differences * \returns Sum of Absolute Differences
*/ */
static unsigned cor_sad(const pixel *pic_data, const pixel *ref_data, static unsigned cor_sad(const pixel *pic_data, const pixel *ref_data,
int block_width, int block_height, unsigned width) int block_width, int block_height, unsigned pic_width)
{ {
pixel ref = *ref_data; pixel ref = *ref_data;
int x, y; int x, y;
@ -721,7 +722,7 @@ static unsigned cor_sad(const pixel *pic_data, const pixel *ref_data,
for (y = 0; y < block_height; ++y) { for (y = 0; y < block_height; ++y) {
for (x = 0; x < block_width; ++x) { for (x = 0; x < block_width; ++x) {
sad += abs(pic_data[y * width + x] - ref); sad += abs(pic_data[y * pic_width + x] - ref);
} }
} }
@ -740,14 +741,14 @@ static unsigned cor_sad(const pixel *pic_data, const pixel *ref_data,
* \returns Sum of Absolute Differences * \returns Sum of Absolute Differences
*/ */
static unsigned ver_sad(const pixel *pic_data, const pixel *ref_data, static unsigned ver_sad(const pixel *pic_data, const pixel *ref_data,
int block_width, int block_height, unsigned width) int block_width, int block_height, unsigned pic_width)
{ {
int x, y; int x, y;
unsigned sad = 0; unsigned sad = 0;
for (y = 0; y < block_height; ++y) { for (y = 0; y < block_height; ++y) {
for (x = 0; x < block_width; ++x) { for (x = 0; x < block_width; ++x) {
sad += abs(pic_data[y * width + x] - ref_data[x]); sad += abs(pic_data[y * pic_width + x] - ref_data[x]);
} }
} }
@ -766,14 +767,14 @@ static unsigned ver_sad(const pixel *pic_data, const pixel *ref_data,
* \returns Sum of Absolute Differences * \returns Sum of Absolute Differences
*/ */
static unsigned hor_sad(const pixel *pic_data, const pixel *ref_data, static unsigned hor_sad(const pixel *pic_data, const pixel *ref_data,
int block_width, int block_height, unsigned width) int block_width, int block_height, unsigned pic_width, unsigned ref_width)
{ {
int x, y; int x, y;
unsigned sad = 0; unsigned sad = 0;
for (y = 0; y < block_height; ++y) { for (y = 0; y < block_height; ++y) {
for (x = 0; x < block_width; ++x) { for (x = 0; x < block_width; ++x) {
sad += abs(pic_data[y * width + x] - ref_data[y * width]); sad += abs(pic_data[y * pic_width + x] - ref_data[y * ref_width]);
} }
} }
@ -795,14 +796,14 @@ static unsigned hor_sad(const pixel *pic_data, const pixel *ref_data,
* \returns Sum of Absolute Differences * \returns Sum of Absolute Differences
*/ */
static unsigned reg_sad(const pixel *data1, const pixel *data2, static unsigned reg_sad(const pixel *data1, const pixel *data2,
int width, int height, unsigned stride) int width, int height, unsigned stride1, unsigned stride2)
{ {
int y, x; int y, x;
unsigned sad = 0; unsigned sad = 0;
for (y = 0; y < height; ++y) { for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) { for (x = 0; x < width; ++x) {
sad += abs((int)data1[y * stride + x] - (int)data2[y * stride + x]); sad += abs((int)data1[y * stride1 + x] - (int)data2[y * stride2 + x]);
} }
} }
@ -827,16 +828,14 @@ static unsigned interpolated_sad(const picture *pic, const picture *ref,
int block_width, int block_height) int block_width, int block_height)
{ {
pixel *pic_data, *ref_data; pixel *pic_data, *ref_data;
int width = pic->width;
int height = pic->height;
int left, right, top, bottom; int left, right, top, bottom;
int result = 0; int result = 0;
// Change the movement vector to point right next to the frame. This doesn't // Change the movement vector to point right next to the frame. This doesn't
// affect the result but removes some special cases. // affect the result but removes some special cases.
if (ref_x > width) ref_x = width; if (ref_x > ref->width) ref_x = ref->width;
if (ref_y > height) ref_y = height; if (ref_y > ref->height) ref_y = ref->height;
if (ref_x + block_width < 0) ref_x = -block_width; if (ref_x + block_width < 0) ref_x = -block_width;
if (ref_y + block_height < 0) ref_y = -block_height; if (ref_y + block_height < 0) ref_y = -block_height;
@ -845,15 +844,15 @@ static unsigned interpolated_sad(const picture *pic, const picture *ref,
// movement vector doesn't point outside the frame. // movement vector doesn't point outside the frame.
left = (ref_x < 0) ? -ref_x : 0; left = (ref_x < 0) ? -ref_x : 0;
top = (ref_y < 0) ? -ref_y : 0; top = (ref_y < 0) ? -ref_y : 0;
right = (ref_x + block_width > width) ? ref_x + block_width - width : 0; right = (ref_x + block_width > ref->width) ? ref_x + block_width - ref->width : 0;
bottom = (ref_y + block_height > height) ? ref_y + block_height - height : 0; bottom = (ref_y + block_height > ref->height) ? ref_y + block_height - ref->height : 0;
// Center picture to the current block and reference to the point where // Center picture to the current block and reference to the point where
// movement vector is pointing to. That point might be outside the buffer, // movement vector is pointing to. That point might be outside the buffer,
// but that is ok because we project the movement vector to the buffer // but that is ok because we project the movement vector to the buffer
// before dereferencing the pointer. // before dereferencing the pointer.
pic_data = &pic->y_data[pic_y * width + pic_x]; pic_data = &pic->y_data[pic_y * pic->width + pic_x];
ref_data = &ref->y_data[ref_y * width + ref_x]; ref_data = &ref->y_data[ref_y * ref->width + ref_x];
// The handling of movement vectors that point outside the picture is done // The handling of movement vectors that point outside the picture is done
// in the following way. // in the following way.
@ -865,86 +864,86 @@ static unsigned interpolated_sad(const picture *pic, const picture *ref,
// being compared is correct. // being compared is correct.
if (top && left) { if (top && left) {
result += cor_sad(pic_data, result += cor_sad(pic_data,
&ref_data[top * width + left], &ref_data[top * ref->width + left],
left, top, width); left, top, pic->width);
result += ver_sad(&pic_data[left], result += ver_sad(&pic_data[left],
&ref_data[top * width + left], &ref_data[top * ref->width + left],
block_width - left, top, width); block_width - left, top, pic->width);
result += hor_sad(&pic_data[top * width], result += hor_sad(&pic_data[top * pic->width],
&ref_data[top * width + left], &ref_data[top * ref->width + left],
left, block_height - top, width); left, block_height - top, pic->width, ref->width);
result += reg_sad(&pic_data[top * width + left], result += reg_sad(&pic_data[top * pic->width + left],
&ref_data[top * width + left], &ref_data[top * ref->width + left],
block_width - left, block_height - top, width); block_width - left, block_height - top, pic->width, ref->width);
} else if (top && right) { } else if (top && right) {
result += ver_sad(pic_data, result += ver_sad(pic_data,
&ref_data[top * width], &ref_data[top * ref->width],
block_width - right, top, width); block_width - right, top, pic->width);
result += cor_sad(&pic_data[block_width - right], result += cor_sad(&pic_data[block_width - right],
&ref_data[top * width + (block_width - right - 1)], &ref_data[top * ref->width + (block_width - right - 1)],
right, top, width); right, top, pic->width);
result += reg_sad(&pic_data[top * width], result += reg_sad(&pic_data[top * pic->width],
&ref_data[top * width], &ref_data[top * ref->width],
block_width - right, block_height - top, width); block_width - right, block_height - top, pic->width, ref->width);
result += hor_sad(&pic_data[top * width + (block_width - right)], result += hor_sad(&pic_data[top * pic->width + (block_width - right)],
&ref_data[top * width + (block_width - right - 1)], &ref_data[top * ref->width + (block_width - right - 1)],
right, block_height - top, width); right, block_height - top, pic->width, ref->width);
} else if (bottom && left) { } else if (bottom && left) {
result += hor_sad(pic_data, result += hor_sad(pic_data,
&ref_data[left], &ref_data[left],
left, block_height - bottom, width); left, block_height - bottom, pic->width, ref->width);
result += reg_sad(&pic_data[left], result += reg_sad(&pic_data[left],
&ref_data[left], &ref_data[left],
block_width - left, block_height - bottom, width); block_width - left, block_height - bottom, pic->width, ref->width);
result += cor_sad(&pic_data[(block_height - bottom) * width], result += cor_sad(&pic_data[(block_height - bottom) * pic->width],
&ref_data[(block_height - bottom - 1) * width + left], &ref_data[(block_height - bottom - 1) * ref->width + left],
left, bottom, width); left, bottom, pic->width);
result += ver_sad(&pic_data[(block_height - bottom) * width + left], result += ver_sad(&pic_data[(block_height - bottom) * pic->width + left],
&ref_data[(block_height - bottom - 1) * width + left], &ref_data[(block_height - bottom - 1) * ref->width + left],
block_width - left, bottom, width); block_width - left, bottom, pic->width);
} else if (bottom && right) { } else if (bottom && right) {
result += reg_sad(pic_data, result += reg_sad(pic_data,
ref_data, ref_data,
block_width - right, block_height - bottom, width); block_width - right, block_height - bottom, pic->width, ref->width);
result += hor_sad(&pic_data[block_width - right], result += hor_sad(&pic_data[block_width - right],
&ref_data[block_width - right - 1], &ref_data[block_width - right - 1],
right, block_height - bottom, width); right, block_height - bottom, pic->width, ref->width);
result += ver_sad(&pic_data[(block_height - bottom) * width], result += ver_sad(&pic_data[(block_height - bottom) * pic->width],
&ref_data[(block_height - bottom - 1) * width], &ref_data[(block_height - bottom - 1) * ref->width],
block_width - right, bottom, width); block_width - right, bottom, pic->width);
result += cor_sad(&pic_data[(block_height - bottom) * width + block_width - right], result += cor_sad(&pic_data[(block_height - bottom) * pic->width + block_width - right],
&ref_data[(block_height - bottom - 1) * width + block_width - right - 1], &ref_data[(block_height - bottom - 1) * ref->width + block_width - right - 1],
right, bottom, width); right, bottom, pic->width);
} else if (top) { } else if (top) {
result += ver_sad(pic_data, result += ver_sad(pic_data,
&ref_data[top * width], &ref_data[top * ref->width],
block_width, top, width); block_width, top, pic->width);
result += reg_sad(&pic_data[top * width], result += reg_sad(&pic_data[top * pic->width],
&ref_data[top * width], &ref_data[top * ref->width],
block_width, block_height - top, width); block_width, block_height - top, pic->width, ref->width);
} else if (bottom) { } else if (bottom) {
result += reg_sad(pic_data, result += reg_sad(pic_data,
ref_data, ref_data,
block_width, block_height - bottom, width); block_width, block_height - bottom, pic->width, ref->width);
result += ver_sad(&pic_data[(block_height - bottom) * width], result += ver_sad(&pic_data[(block_height - bottom) * pic->width],
&ref_data[(block_height - bottom - 1) * width], &ref_data[(block_height - bottom - 1) * ref->width],
block_width, bottom, width); block_width, bottom, pic->width);
} else if (left) { } else if (left) {
result += hor_sad(pic_data, result += hor_sad(pic_data,
&ref_data[left], &ref_data[left],
left, block_height, width); left, block_height, pic->width, ref->width);
result += reg_sad(&pic_data[left], result += reg_sad(&pic_data[left],
&ref_data[left], &ref_data[left],
block_width - left, block_height, width); block_width - left, block_height, pic->width, ref->width);
} else if (right) { } else if (right) {
result += reg_sad(pic_data, result += reg_sad(pic_data,
ref_data, ref_data,
block_width - right, block_height, width); block_width - right, block_height, pic->width, ref->width);
result += hor_sad(&pic_data[block_width - right], result += hor_sad(&pic_data[block_width - right],
&ref_data[block_width - right - 1], &ref_data[block_width - right - 1],
right, block_height, width); right, block_height, pic->width, ref->width);
} else { } else {
result += reg_sad(pic_data, ref_data, block_width, block_height, width); result += reg_sad(pic_data, ref_data, block_width, block_height, pic->width, ref->width);
} }
return result; return result;
@ -967,14 +966,16 @@ unsigned calc_sad(const picture *pic, const picture *ref,
int pic_x, int pic_y, int ref_x, int ref_y, int pic_x, int pic_y, int ref_x, int ref_y,
int block_width, int block_height) int block_width, int block_height)
{ {
if (ref_x >= 0 && ref_x <= pic->width - block_width && assert(pic_x >= 0 && pic_x <= pic->width - block_width);
ref_y >= 0 && ref_y <= pic->height - block_height) assert(pic_y >= 0 && pic_y <= pic->height - block_height);
if (ref_x >= 0 && ref_x <= ref->width - block_width &&
ref_y >= 0 && ref_y <= ref->height - block_height)
{ {
// Reference block is completely inside the frame, so just calculate the // Reference block is completely inside the frame, so just calculate the
// SAD directly. This is the most common case, which is why it's first. // SAD directly. This is the most common case, which is why it's first.
const pixel *pic_data = &pic->y_data[pic_y * pic->width + pic_x]; const pixel *pic_data = &pic->y_data[pic_y * pic->width + pic_x];
const pixel *ref_data = &ref->y_data[ref_y * pic->width + ref_x]; const pixel *ref_data = &ref->y_data[ref_y * ref->width + ref_x];
return reg_sad(pic_data, ref_data, block_width, block_height, pic->width); return reg_sad(pic_data, ref_data, block_width, block_height, pic->width, ref->width);
} else { } else {
// Call a routine that knows how to interpolate pixels outside the frame. // Call a routine that knows how to interpolate pixels outside the frame.
return interpolated_sad(pic, ref, pic_x, pic_y, ref_x, ref_y, block_width, block_height); return interpolated_sad(pic, ref, pic_x, pic_y, ref_x, ref_y, block_width, block_height);