[FFmpeg-devel] [PATCH] libavfilter image transformations

Alexander Strange astrange
Wed Apr 21 04:26:54 CEST 2010


On Apr 20, 2010, at 5:03 PM, Daniel G. Taylor wrote:

> Hey,
> 
> Attached is a patch to add matrix transformation utility methods to libavfilter. These are useful for translation, rotation, scaling, etc of input pictures and can be easily used from any filter.
> 
> This code was originally part of my work on the deshake/stabilize filter and the work of Georg Martius from his transcode transform filter.
> 
> Example usage:
> 
> #include "transform.h"
> 
> ...
> double matrix[9];
> 
> avfilter_get_matrix(shift_x, shift_y, radians, scale, (double *) &matrix);
> avfilter_transform(src, dst, src_stride, dst_stride, width, height, &matrix, INTERPOLATE_BILINEAR, FILL_MIRROR);
> ...
> 
> The code supports creating simple matrices from translation, rotation, and scaling parameters, adding/subtracting matrices, multiplying a matrix by a scalar, and doing the actual picture transform. It supports several types of interpolation and edge fill methods.
> 
> This is useful for any filter that might want to transform video frames in any way in the future. I have at least one filter that will use this but is waiting on motion estimation stuff (deshake/stabilize video).

First, are these transforms separable? I'm not familiar with affine rotations to know how to split them into 1D.

Second, can they be done in fixed-point?

Third, can it be merged with swscale? Though that looks hard, filters should be using it for scaling and transformation if possible.

> +#define INTERPOLATE_METHOD(name) static uint8_t name(float x, float y, const uint8_t *src, int width, int height, int stride, uint8_t def)
> +
> +#define PIXEL(img, x, y, w, h, stride, def) ((x) < 0 || (y) < 0) ? (def) : (((x) >= (w) || (y) >= (h)) ? (def) : img[(x) + (y) * (stride)])

Break these lines after the macro name.

> +        return PIXEL(src, (int)round(x), (int)round(y), width, height, stride, def);

Should be roundf(), and then it should be lrintf(). Unless (int)(x + .5f) is faster.
(Of course, ignore all of this if you can do it in fixed-point)

> +/**
> + * Bilinear interpolation
> + */


This won't work for downscaling because it won't sample any more than 4 source pixels. Same for the other methods.

> +        return (uint8_t) s;

The cast doesn't do anything.

> +/**
> + * Biquadratic interpolation
> + */

If you're going to provide something better than linear, at least make it bicubic or slower than that. swscale has several good kernels.

> +        x_c = (int)ceilf(x);
> +        x_f = (int)floorf(x);
> +        y_c = (int)ceilf(y);
> +        y_f = (int)floorf(y);

These casts are unnecessary too.

> +void avfilter_get_matrix(double x_shift, double y_shift, double angle, double zoom, double *matrix) {
> +    matrix[0] = zoom * cos(angle);
> +    matrix[1] = -sin(angle);
> +    matrix[2] = x_shift;
> +    matrix[3] = -matrix[1];
> +    matrix[4] = matrix[0];
> +    matrix[5] = y_shift;
> +    matrix[6] = 0;
> +    matrix[7] = 0;
> +    matrix[8] = 1;
> +}

Use float instead of double unless it's really unstable.

Just use a loop for add/sub/mul.

> +void avfilter_transform(const uint8_t *src, uint8_t *dst, int src_stride, int dst_stride, int width, int height, const double *matrix, enum InterpolateMethod interpolate, enum FillMethod fill)

This line is too long.

> +                case FILL_EXTRUDE:

Call it CLAMP, maybe?

> +                    def = src[(int)((y_s < 0) ? -y_s : (y_s >= height) ? (height + height - y_s) : y_s) * src_stride + (int)((x_s < 0) ? -x_s : (x_s >= width) ? (width + width - x_s) : x_s)];

Split this into multiple statements so the lines are shorter.





More information about the ffmpeg-devel mailing list