summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>2014-10-13 16:19:19 +0200
committerXiang, Haihao <haihao.xiang@intel.com>2014-12-24 08:46:34 +0800
commitb21a650d58cdbe128a6e96b9a7b63faae9c53432 (patch)
tree92e418216772cee9d512c426b31a3f73f9c5c5ec
parentb83ce01349720bdaa712cec67d63fc426ef2331f (diff)
downloadlibva-intel-driver-b21a650d58cdbe128a6e96b9a7b63faae9c53432.tar.gz
vpp: add support for high-quality scaling.
Add support for high-quality scaling during video processing. This is enabled with the VA_FILTER_SCALING_HQ filter flag. The algorithm used for that is based on a Lanczos convolution kernel: 3 lobes on either side for luma samples, and 2 lobes on either side for chroma samples. v2: fixed rounding precision for normalized coefficients. Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
-rw-r--r--src/i965_vpp_avs.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/i965_vpp_avs.c b/src/i965_vpp_avs.c
index 12f1dfe4..eae141ea 100644
--- a/src/i965_vpp_avs.c
+++ b/src/i965_vpp_avs.c
@@ -43,6 +43,15 @@ avs_init_coeffs(float *coeffs, int num_coeffs)
#endif
}
+/* Computes the sinc(x) function */
+static float
+avs_sinc(float x)
+{
+ if (x == 0.0f)
+ return 1.0f;
+ return sin(x * M_PI) / (x * M_PI);
+}
+
/* Convolution kernel for linear interpolation */
static float
avs_kernel_linear(float x)
@@ -52,6 +61,68 @@ avs_kernel_linear(float x)
return abs_x < 1.0f ? 1 - abs_x : 0.0f;
}
+/* Convolution kernel for Lanczos-based interpolation */
+static float
+avs_kernel_lanczos(float x, float a)
+{
+ const float abs_x = fabsf(x);
+
+ return abs_x < a ? avs_sinc(x) * avs_sinc(x / a) : 0.0f;
+}
+
+/* Truncates floating-point value towards an epsilon factor */
+static inline float
+avs_trunc_coeff(float x, float epsilon)
+{
+ return rintf(x / epsilon) * epsilon;
+}
+
+/* Normalize coefficients for one sample/direction */
+static void
+avs_normalize_coeffs_1(float *coeffs, int num_coeffs, float epsilon)
+{
+ float s, sum = 0.0;
+ int i, c, r, r1;
+
+ for (i = 0; i < num_coeffs; i++)
+ sum += coeffs[i];
+
+ if (sum < epsilon)
+ return;
+
+ s = 0.0;
+ for (i = 0; i < num_coeffs; i++)
+ s += (coeffs[i] = avs_trunc_coeff(coeffs[i] / sum, epsilon));
+
+ /* Distribute the remaining bits, while allocating more to the center */
+ c = num_coeffs/2;
+ c = c - (coeffs[c - 1] > coeffs[c]);
+
+ r = (1.0f - s) / epsilon;
+ r1 = r / 4;
+ if (coeffs[c + 1] == 0.0f)
+ coeffs[c] += r * epsilon;
+ else {
+ coeffs[c] += (r - 2*r1) * epsilon;
+ coeffs[c - 1] += r1 * epsilon;
+ coeffs[c + 1] += r1 * epsilon;
+ }
+}
+
+/* Normalize all coefficients so that their sum yields 1.0f */
+static void
+avs_normalize_coeffs(AVSCoeffs *coeffs, const AVSConfig *config)
+{
+ avs_normalize_coeffs_1(coeffs->y_k_h, config->num_luma_coeffs,
+ config->coeff_epsilon);
+ avs_normalize_coeffs_1(coeffs->y_k_v, config->num_luma_coeffs,
+ config->coeff_epsilon);
+ avs_normalize_coeffs_1(coeffs->uv_k_h, config->num_chroma_coeffs,
+ config->coeff_epsilon);
+ avs_normalize_coeffs_1(coeffs->uv_k_v, config->num_chroma_coeffs,
+ config->coeff_epsilon);
+}
+
/* Generate coefficients for default quality (bilinear) */
static void
avs_gen_coeffs_linear(float *coeffs, int num_coeffs, int phase, int num_phases,
@@ -65,6 +136,22 @@ avs_gen_coeffs_linear(float *coeffs, int num_coeffs, int phase, int num_phases,
coeffs[c + 1] = avs_kernel_linear(p - 1);
}
+/* Generate coefficients for high quality (lanczos) */
+static void
+avs_gen_coeffs_lanczos(float *coeffs, int num_coeffs, int phase, int num_phases,
+ float f)
+{
+ const int c = num_coeffs/2 - 1;
+ const int l = num_coeffs > 4 ? 3 : 2;
+ const float p = (float)phase / (num_phases*2);
+ int i;
+
+ if (f > 1.0f)
+ f = 1.0f;
+ for (i = 0; i < num_coeffs; i++)
+ coeffs[i] = avs_kernel_lanczos((i - (c + p)) * f, l);
+}
+
/* Generate coefficients with the supplied scaler */
static void
avs_gen_coeffs(AVSState *avs, float sx, float sy, AVSGenCoeffsFunc gen_coeffs)
@@ -83,6 +170,8 @@ avs_gen_coeffs(AVSState *avs, float sx, float sy, AVSGenCoeffsFunc gen_coeffs)
i, config->num_phases, sy);
gen_coeffs(coeffs->uv_k_v, config->num_chroma_coeffs,
i, config->num_phases, sy);
+
+ avs_normalize_coeffs(coeffs, config);
}
}
@@ -101,6 +190,9 @@ avs_update_coefficients(AVSState *avs, float sx, float sy, uint32_t flags)
flags &= VA_FILTER_SCALING_MASK;
switch (flags) {
+ case VA_FILTER_SCALING_HQ:
+ gen_coeffs = avs_gen_coeffs_lanczos;
+ break;
default:
gen_coeffs = avs_gen_coeffs_linear;
break;