[Libva] [PATCH intel-driver v2 4/8] vpp: add support for high-quality scaling.

Gwenole Beauchesne gb.devel at gmail.com
Tue Oct 28 10:51:48 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 12f1dfe..2dfaecd 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);
     }
 }
 
@@ -101,6 +184,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;
-- 
1.9.1



More information about the Libva mailing list