]> git.sesse.net Git - ffmpeg/blob - libavfilter/transform.c
libavfilter: image transform code
[ffmpeg] / libavfilter / transform.c
1 /*
2  * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
3  * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file libavfilter/transform.c
24  * transform input video
25  */
26
27 #include "libavutil/common.h"
28
29 #include "transform.h"
30
31 #define INTERPOLATE_METHOD(name) \
32     static uint8_t name(float x, float y, const uint8_t *src, \
33                         int width, int height, int stride, uint8_t def)
34
35 #define PIXEL(img, x, y, w, h, stride, def) \
36     ((x) < 0 || (y) < 0) ? (def) : \
37     (((x) >= (w) || (y) >= (h)) ? (def) : \
38     img[(x) + (y) * (stride)])
39
40 /**
41  * Nearest neighbor interpolation
42  */
43 INTERPOLATE_METHOD(interpolate_nearest)
44 {
45     return PIXEL(src, (int)(x + 0.5), (int)(y + 0.5), width, height, stride, def);
46 }
47
48 /**
49  * Bilinear interpolation
50  */
51 INTERPOLATE_METHOD(interpolate_bilinear)
52 {
53     int x_c, x_f, y_c, y_f;
54     int v1, v2, v3, v4;
55
56     if (x < -1 || x > width || y < -1 || y > height) {
57         return def;
58     } else {
59         x_f = (int)x;
60         x_c = x_f + 1;
61
62         y_f = (int)y;
63         y_c = y_f + 1;
64
65         v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
66         v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
67         v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
68         v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
69
70         return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
71                 v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
72     }
73 }
74
75 /**
76  * Biquadratic interpolation
77  */
78 INTERPOLATE_METHOD(interpolate_biquadratic)
79 {
80     int     x_c, x_f, y_c, y_f;
81     uint8_t v1,  v2,  v3,  v4;
82     float   f1,  f2,  f3,  f4;
83
84     if (x < - 1 || x > width || y < -1 || y > height)
85         return def;
86     else {
87         x_f = (int)x;
88         x_c = x_f + 1;
89         y_f = (int)y;
90         y_c = y_f + 1;
91
92         v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
93         v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
94         v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
95         v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
96
97         f1 = 1 - sqrt((x_c - x) * (y_c - y));
98         f2 = 1 - sqrt((x_c - x) * (y - y_f));
99         f3 = 1 - sqrt((x - x_f) * (y_c - y));
100         f4 = 1 - sqrt((x - x_f) * (y - y_f));
101         return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
102     }
103 }
104
105 void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix) {
106     matrix[0] = zoom * cos(angle);
107     matrix[1] = -sin(angle);
108     matrix[2] = x_shift;
109     matrix[3] = -matrix[1];
110     matrix[4] = matrix[0];
111     matrix[5] = y_shift;
112     matrix[6] = 0;
113     matrix[7] = 0;
114     matrix[8] = 1;
115 }
116
117 void avfilter_add_matrix(const float *m1, const float *m2, float *result)
118 {
119     for (int i = 0; i < 9; i++)
120         result[i] = m1[i] + m2[i];
121 }
122
123 void avfilter_sub_matrix(const float *m1, const float *m2, float *result)
124 {
125     for (int i = 0; i < 9; i++)
126         result[i] = m1[i] - m2[i];
127 }
128
129 void avfilter_mul_matrix(const float *m1, float scalar, float *result)
130 {
131     for (int i = 0; i < 9; i++)
132         result[i] = m1[i] * scalar;
133 }
134
135 void avfilter_transform(const uint8_t *src, uint8_t *dst,
136                         int src_stride, int dst_stride,
137                         int width, int height, const float *matrix,
138                         enum InterpolateMethod interpolate,
139                         enum FillMethod fill)
140 {
141     int x, y;
142     float x_s, y_s;
143     uint8_t def = 0;
144     uint8_t (*func)(float, float, const uint8_t *, int, int, int, uint8_t) = NULL;
145
146     switch(interpolate) {
147         case INTERPOLATE_NEAREST:
148             func = interpolate_nearest;
149             break;
150         case INTERPOLATE_BILINEAR:
151             func = interpolate_bilinear;
152             break;
153         case INTERPOLATE_BIQUADRATIC:
154             func = interpolate_biquadratic;
155             break;
156     }
157
158     for (y = 0; y < height; y++) {
159         for(x = 0; x < width; x++) {
160             x_s = x * matrix[0] + y * matrix[1] + matrix[2];
161             y_s = x * matrix[3] + y * matrix[4] + matrix[5];
162
163             switch(fill) {
164                 case FILL_ORIGINAL:
165                     def = src[y * src_stride + x];
166                     break;
167                 case FILL_CLAMP:
168                     y_s = av_clipf(y_s, 0, height - 1);
169                     x_s = av_clipf(x_s, 0, width - 1);
170                     def = src[(int)y_s * src_stride + (int)x_s];
171                     break;
172                 case FILL_MIRROR:
173                     y_s = (y_s < 0) ? -y_s : (y_s >= height) ? (height + height - y_s) : y_s;
174                     x_s = (x_s < 0) ? -x_s : (x_s >= width) ? (width + width - x_s) : x_s;
175                     def = src[(int)y_s * src_stride + (int)x_s];
176             }
177
178             dst[y * dst_stride + x] = func(x_s, y_s, src, width, height, src_stride, def);
179         }
180     }
181 }
182