Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 | |
24 | * transform input video | |
25 | */ | |
26 | ||
27 | #include "libavutil/common.h" | |
28 | #include "libavutil/avassert.h" | |
29 | ||
30 | #include "transform.h" | |
31 | ||
32 | #define INTERPOLATE_METHOD(name) \ | |
33 | static uint8_t name(float x, float y, const uint8_t *src, \ | |
34 | int width, int height, int stride, uint8_t def) | |
35 | ||
36 | #define PIXEL(img, x, y, w, h, stride, def) \ | |
37 | ((x) < 0 || (y) < 0) ? (def) : \ | |
38 | (((x) >= (w) || (y) >= (h)) ? (def) : \ | |
39 | img[(x) + (y) * (stride)]) | |
40 | ||
41 | /** | |
42 | * Nearest neighbor interpolation | |
43 | */ | |
44 | INTERPOLATE_METHOD(interpolate_nearest) | |
45 | { | |
46 | return PIXEL(src, (int)(x + 0.5), (int)(y + 0.5), width, height, stride, def); | |
47 | } | |
48 | ||
49 | /** | |
50 | * Bilinear interpolation | |
51 | */ | |
52 | INTERPOLATE_METHOD(interpolate_bilinear) | |
53 | { | |
54 | int x_c, x_f, y_c, y_f; | |
55 | int v1, v2, v3, v4; | |
56 | ||
57 | if (x < -1 || x > width || y < -1 || y > height) { | |
58 | return def; | |
59 | } else { | |
60 | x_f = (int)x; | |
61 | x_c = x_f + 1; | |
62 | ||
63 | y_f = (int)y; | |
64 | y_c = y_f + 1; | |
65 | ||
66 | v1 = PIXEL(src, x_c, y_c, width, height, stride, def); | |
67 | v2 = PIXEL(src, x_c, y_f, width, height, stride, def); | |
68 | v3 = PIXEL(src, x_f, y_c, width, height, stride, def); | |
69 | v4 = PIXEL(src, x_f, y_f, width, height, stride, def); | |
70 | ||
71 | return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) + | |
72 | v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y))); | |
73 | } | |
74 | } | |
75 | ||
76 | /** | |
77 | * Biquadratic interpolation | |
78 | */ | |
79 | INTERPOLATE_METHOD(interpolate_biquadratic) | |
80 | { | |
81 | int x_c, x_f, y_c, y_f; | |
82 | uint8_t v1, v2, v3, v4; | |
83 | float f1, f2, f3, f4; | |
84 | ||
85 | if (x < - 1 || x > width || y < -1 || y > height) | |
86 | return def; | |
87 | else { | |
88 | x_f = (int)x; | |
89 | x_c = x_f + 1; | |
90 | y_f = (int)y; | |
91 | y_c = y_f + 1; | |
92 | ||
93 | v1 = PIXEL(src, x_c, y_c, width, height, stride, def); | |
94 | v2 = PIXEL(src, x_c, y_f, width, height, stride, def); | |
95 | v3 = PIXEL(src, x_f, y_c, width, height, stride, def); | |
96 | v4 = PIXEL(src, x_f, y_f, width, height, stride, def); | |
97 | ||
98 | f1 = 1 - sqrt((x_c - x) * (y_c - y)); | |
99 | f2 = 1 - sqrt((x_c - x) * (y - y_f)); | |
100 | f3 = 1 - sqrt((x - x_f) * (y_c - y)); | |
101 | f4 = 1 - sqrt((x - x_f) * (y - y_f)); | |
102 | return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4); | |
103 | } | |
104 | } | |
105 | ||
106 | void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix) { | |
107 | matrix[0] = zoom * cos(angle); | |
108 | matrix[1] = -sin(angle); | |
109 | matrix[2] = x_shift; | |
110 | matrix[3] = -matrix[1]; | |
111 | matrix[4] = matrix[0]; | |
112 | matrix[5] = y_shift; | |
113 | matrix[6] = 0; | |
114 | matrix[7] = 0; | |
115 | matrix[8] = 1; | |
116 | } | |
117 | ||
118 | void avfilter_add_matrix(const float *m1, const float *m2, float *result) | |
119 | { | |
120 | int i; | |
121 | for (i = 0; i < 9; i++) | |
122 | result[i] = m1[i] + m2[i]; | |
123 | } | |
124 | ||
125 | void avfilter_sub_matrix(const float *m1, const float *m2, float *result) | |
126 | { | |
127 | int i; | |
128 | for (i = 0; i < 9; i++) | |
129 | result[i] = m1[i] - m2[i]; | |
130 | } | |
131 | ||
132 | void avfilter_mul_matrix(const float *m1, float scalar, float *result) | |
133 | { | |
134 | int i; | |
135 | for (i = 0; i < 9; i++) | |
136 | result[i] = m1[i] * scalar; | |
137 | } | |
138 | ||
139 | static inline int mirror(int v, int m) | |
140 | { | |
141 | while ((unsigned)v > (unsigned)m) { | |
142 | v = -v; | |
143 | if (v < 0) | |
144 | v += 2 * m; | |
145 | } | |
146 | return v; | |
147 | } | |
148 | ||
149 | int avfilter_transform(const uint8_t *src, uint8_t *dst, | |
150 | int src_stride, int dst_stride, | |
151 | int width, int height, const float *matrix, | |
152 | enum InterpolateMethod interpolate, | |
153 | enum FillMethod fill) | |
154 | { | |
155 | int x, y; | |
156 | float x_s, y_s; | |
157 | uint8_t def = 0; | |
158 | uint8_t (*func)(float, float, const uint8_t *, int, int, int, uint8_t) = NULL; | |
159 | ||
160 | switch(interpolate) { | |
161 | case INTERPOLATE_NEAREST: | |
162 | func = interpolate_nearest; | |
163 | break; | |
164 | case INTERPOLATE_BILINEAR: | |
165 | func = interpolate_bilinear; | |
166 | break; | |
167 | case INTERPOLATE_BIQUADRATIC: | |
168 | func = interpolate_biquadratic; | |
169 | break; | |
170 | default: | |
171 | return AVERROR(EINVAL); | |
172 | } | |
173 | ||
174 | for (y = 0; y < height; y++) { | |
175 | for(x = 0; x < width; x++) { | |
176 | x_s = x * matrix[0] + y * matrix[1] + matrix[2]; | |
177 | y_s = x * matrix[3] + y * matrix[4] + matrix[5]; | |
178 | ||
179 | switch(fill) { | |
180 | case FILL_ORIGINAL: | |
181 | def = src[y * src_stride + x]; | |
182 | break; | |
183 | case FILL_CLAMP: | |
184 | y_s = av_clipf(y_s, 0, height - 1); | |
185 | x_s = av_clipf(x_s, 0, width - 1); | |
186 | def = src[(int)y_s * src_stride + (int)x_s]; | |
187 | break; | |
188 | case FILL_MIRROR: | |
189 | x_s = mirror(x_s, width-1); | |
190 | y_s = mirror(y_s, height-1); | |
191 | ||
192 | av_assert2(x_s >= 0 && y_s >= 0); | |
193 | av_assert2(x_s < width && y_s < height); | |
194 | def = src[(int)y_s * src_stride + (int)x_s]; | |
195 | } | |
196 | ||
197 | dst[y * dst_stride + x] = func(x_s, y_s, src, width, height, src_stride, def); | |
198 | } | |
199 | } | |
200 | return 0; | |
201 | } |