[Libva] [PATCH intel-driver 4/8] vpp: add support for high-quality scaling.
Gwenole Beauchesne
gb.devel at gmail.com
Mon Oct 13 10:27:43 PDT 2014
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.
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne at intel.com>
---
src/i965_vpp_avs.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/src/i965_vpp_avs.c b/src/i965_vpp_avs.c
index 39407ac..33d6eba 100644
--- a/src/i965_vpp_avs.c
+++ b/src/i965_vpp_avs.c
@@ -52,6 +52,72 @@ 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);
+
+ if (abs_x == 0.0f)
+ return 1.0;
+ if (abs_x < a)
+ return a * sin(x * M_PI) * sin((x * M_PI) / a) / (M_PI * M_PI * x * x);
+ return 0.0f;
+}
+
+/* Truncates floating-point value towards an epsilon factor */
+static inline float
+avs_trunc_coeff(float x, float epsilon)
+{
+ return floorf(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 +131,21 @@ 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 float p = (float)phase / (num_phases*2);
+ int i, l = 2;
+
+ l = num_coeffs > 4 ? 3 : 2;
+ f = 1.0f / ceilf(1.0f/f);
+ 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 +164,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);
}
}
@@ -100,6 +183,9 @@ avs_update_coefficients(AVSState *avs, float sx, float sy, uint32_t flags)
AVSGenCoeffsFunc gen_coeffs;
switch (flags & VA_FILTER_SCALING_MASK) {
+ case VA_FILTER_SCALING_HQ:
+ gen_coeffs = avs_gen_coeffs_lanczos;
+ break;
default:
gen_coeffs = avs_gen_coeffs_linear;
break;
--
1.9.1
More information about the Libva
mailing list