1 /*****************************************************************************
2 * transform.c : transform image module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2006 VLC authors and VideoLAN
5 * Copyright (C) 2010 Laurent Aimar
6 * Copyright (C) 2012 RĂ©mi Denis-Courmont
8 * Authors: Samuel Hocevar <sam@zoy.org>
9 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Open (vlc_object_t *);
43 static void Close(vlc_object_t *);
45 #define CFG_PREFIX "transform-"
47 #define TYPE_TEXT N_("Transform type")
48 static const char * const type_list[] = { "90", "180", "270",
49 "hflip", "vflip", "transpose", "antitranspose" };
50 static const char * const type_list_text[] = { N_("Rotate by 90 degrees"),
51 N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
52 N_("Flip horizontally"), N_("Flip vertically"),
53 N_("Transpose"), N_("Anti-transpose") };
56 set_description(N_("Video transformation filter"))
57 set_shortname(N_("Transformation"))
58 set_help(N_("Rotate or flip the video"))
59 set_capability("video filter2", 0)
60 set_category(CAT_VIDEO)
61 set_subcategory(SUBCAT_VIDEO_VFILTER)
63 add_string(CFG_PREFIX "type", "90", TYPE_TEXT, TYPE_TEXT, false)
64 change_string_list(type_list, type_list_text)
67 add_shortcut("transform")
68 set_callbacks(Open, Close)
71 /*****************************************************************************
73 *****************************************************************************/
74 static void HFlip(int *sx, int *sy, int w, int h, int dx, int dy)
80 static void VFlip(int *sx, int *sy, int w, int h, int dx, int dy)
86 static void Transpose(int *sx, int *sy, int w, int h, int dx, int dy)
88 VLC_UNUSED( h ); VLC_UNUSED( w );
92 static void AntiTranspose(int *sx, int *sy, int w, int h, int dx, int dy)
97 static void R90(int *sx, int *sy, int w, int h, int dx, int dy)
103 static void R180(int *sx, int *sy, int w, int h, int dx, int dy)
108 static void R270(int *sx, int *sy, int w, int h, int dx, int dy)
114 typedef void (*convert_t)(int *, int *, int, int, int, int);
116 #define PLANE(f,bits) \
117 static void Plane##bits##_##f(plane_t *restrict dst, const plane_t *restrict src) \
119 const uint##bits##_t *src_pixels = (const void *)src->p_pixels; \
120 uint##bits##_t *restrict dst_pixels = (void *)dst->p_pixels; \
121 const unsigned src_width = src->i_pitch / sizeof (*src_pixels); \
122 const unsigned dst_width = dst->i_pitch / sizeof (*dst_pixels); \
123 const unsigned dst_visible_width = dst->i_visible_pitch / sizeof (*dst_pixels); \
125 for (int y = 0; y < dst->i_visible_lines; y++) { \
126 for (unsigned x = 0; x < dst_visible_width; x++) { \
128 (f)(&sx, &sy, dst_visible_width, dst->i_visible_lines, x, y); \
129 dst_pixels[y * dst_width + x] = \
130 src_pixels[sy * src_width + sx]; \
135 static void Plane_VFlip(plane_t *restrict dst, const plane_t *restrict src)
137 const uint8_t *src_pixels = src->p_pixels;
138 uint8_t *restrict dst_pixels = dst->p_pixels;
140 dst_pixels += dst->i_pitch * dst->i_visible_lines;
141 for (int y = 0; y < dst->i_visible_lines; y++) {
142 dst_pixels -= dst->i_pitch;
143 memcpy(dst_pixels, src_pixels, dst->i_visible_pitch);
144 src_pixels += src->i_pitch;
149 static void PlaneYUY2_##f(plane_t *restrict dst, const plane_t *restrict src) \
151 unsigned dst_visible_width = dst->i_visible_pitch / 2; \
153 for (int y = 0; y < dst->i_visible_lines; y += 2) { \
154 for (unsigned x = 0; x < dst_visible_width; x+= 2) { \
155 int sx0, sy0, sx1, sy1; \
156 (f)(&sx0, &sy0, dst_visible_width, dst->i_visible_lines, x, y); \
157 (f)(&sx1, &sy1, dst_visible_width, dst->i_visible_lines, \
159 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 0)] = \
160 src->p_pixels[sy0 * src->i_pitch + 2 * sx0]; \
161 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 1)] = \
162 src->p_pixels[sy1 * src->i_pitch + 2 * sx0]; \
163 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 0)] = \
164 src->p_pixels[sy0 * src->i_pitch + 2 * sx1]; \
165 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 1)] = \
166 src->p_pixels[sy1 * src->i_pitch + 2 * sx1]; \
169 (f)(&sx, &sy, dst_visible_width / 2, dst->i_visible_lines / 2, \
171 u = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 1] + \
172 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 1]) / 2; \
173 v = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 3] + \
174 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 3]) / 2; \
175 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 1] = u; \
176 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 3] = v; \
177 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 1] = u; \
178 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 3] = v; \
184 PLANE(f,8) PLANE(f,16) PLANE(f,32)
187 #define Plane8_VFlip Plane_VFlip
188 #define Plane16_VFlip Plane_VFlip
189 #define Plane32_VFlip Plane_VFlip
191 PLANES(AntiTranspose)
196 #define PlaneYUY2_HFlip Plane32_HFlip
197 #define PlaneYUY2_VFlip Plane_VFlip
198 #define PlaneYUY2_R180 Plane32_R180
208 void (*plane8) (plane_t *dst, const plane_t *src);
209 void (*plane16)(plane_t *dst, const plane_t *src);
210 void (*plane32)(plane_t *dst, const plane_t *src);
211 void (*yuyv)(plane_t *dst, const plane_t *src);
212 } transform_description_t;
214 #define DESC(str, f, invf) \
215 { str, f, invf, Plane8_##f, Plane16_##f, Plane32_##f, PlaneYUY2_##f }
217 static const transform_description_t descriptions[] = {
218 DESC("90", R90, R270),
219 DESC("180", R180, R180),
220 DESC("270", R270, R90),
221 DESC("hflip", HFlip, HFlip),
222 DESC("vflip", VFlip, VFlip),
223 DESC("transpose", Transpose, Transpose),
224 DESC("antitranspose", AntiTranspose, AntiTranspose),
227 static bool dsc_is_rotated(const transform_description_t *dsc)
229 return dsc->plane32 != dsc->yuyv;
232 static const size_t n_transforms =
233 sizeof (descriptions) / sizeof (descriptions[0]);
235 struct filter_sys_t {
236 const vlc_chroma_description_t *chroma;
237 void (*plane)(plane_t *, const plane_t *);
241 static picture_t *Filter(filter_t *filter, picture_t *src)
243 filter_sys_t *sys = filter->p_sys;
245 picture_t *dst = filter_NewPicture(filter);
247 picture_Release(src);
251 const vlc_chroma_description_t *chroma = sys->chroma;
252 for (unsigned i = 0; i < chroma->plane_count; i++)
253 sys->plane(&dst->p[i], &src->p[i]);
255 picture_CopyProperties(dst, src);
256 picture_Release(src);
260 static int Mouse(filter_t *filter, vlc_mouse_t *mouse,
261 const vlc_mouse_t *mold, const vlc_mouse_t *mnew)
265 const video_format_t *fmt = &filter->fmt_out.video;
266 const filter_sys_t *sys = filter->p_sys;
269 sys->convert(&mouse->i_x, &mouse->i_y,
270 fmt->i_visible_width, fmt->i_visible_height,
271 mouse->i_x, mouse->i_y);
275 static int Open(vlc_object_t *object)
277 filter_t *filter = (filter_t *)object;
278 const video_format_t *src = &filter->fmt_in.video;
279 video_format_t *dst = &filter->fmt_out.video;
281 const vlc_chroma_description_t *chroma =
282 vlc_fourcc_GetChromaDescription(src->i_chroma);
286 filter_sys_t *sys = malloc(sizeof(*sys));
290 sys->chroma = chroma;
292 char *type_name = var_InheritString(filter, CFG_PREFIX"type");
293 const transform_description_t *dsc = NULL;
295 for (size_t i = 0; i < n_transforms; i++)
296 if (type_name && !strcmp(descriptions[i].name, type_name)) {
297 dsc = &descriptions[i];
301 dsc = &descriptions[0];
302 msg_Warn(filter, "No valid transform mode provided, using '%s'",
308 switch (chroma->pixel_size) {
310 sys->plane = dsc->plane8;
313 sys->plane = dsc->plane16;
316 sys->plane = dsc->plane32;
319 msg_Err(filter, "Unsupported pixel size %u (chroma %4.4s)",
320 chroma->pixel_size, (char *)&src->i_chroma);
324 sys->convert = dsc->convert;
325 if (dsc_is_rotated(dsc)) {
326 for (unsigned i = 0; i < chroma->plane_count; i++) {
327 if (chroma->p[i].w.num * chroma->p[i].h.den
328 != chroma->p[i].h.num * chroma->p[i].w.den) {
329 msg_Err(filter, "Format rotation not possible (chroma %4.4s)",
330 (char *)&src->i_chroma); /* I422... */
335 if (!filter->b_allow_fmt_out_change) {
336 msg_Err(filter, "Format change is not allowed");
340 dst->i_width = src->i_height;
341 dst->i_visible_width = src->i_visible_height;
342 dst->i_height = src->i_width;
343 dst->i_visible_height = src->i_visible_width;
344 dst->i_sar_num = src->i_sar_den;
345 dst->i_sar_den = src->i_sar_num;
348 /* Deal with weird packed formats */
349 switch (src->i_chroma) {
352 if (dsc_is_rotated(dsc)) {
353 msg_Err(filter, "Format rotation not possible (chroma %4.4s)",
354 (char *)&src->i_chroma);
360 sys->plane = dsc->yuyv; /* 32-bits, not 16-bits! */
367 dst->i_x_offset = INT_MAX;
368 dst->i_y_offset = INT_MAX;
369 for (int i = 0; i < 2; i++) {
371 dsc->iconvert(&tx, &ty, src->i_width, src->i_height,
372 src->i_x_offset + i * (src->i_visible_width - 1),
373 src->i_y_offset + i * (src->i_visible_height - 1));
374 dst->i_x_offset = __MIN(dst->i_x_offset, (unsigned)(1 + tx));
375 dst->i_y_offset = __MIN(dst->i_y_offset, (unsigned)(1 + ty));
379 filter->pf_video_filter = Filter;
380 filter->pf_video_mouse = Mouse;
387 static void Close(vlc_object_t *object)
389 filter_t *filter = (filter_t *)object;
390 filter_sys_t *sys = filter->p_sys;