1 /*****************************************************************************
2 * transform.c : transform image module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2006 the VideoLAN team
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
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 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 General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, 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, 0)
66 add_shortcut("transform")
67 set_callbacks(Open, Close)
70 /*****************************************************************************
72 *****************************************************************************/
73 static void HFlip(int *sx, int *sy, int w, int h, int dx, int dy)
79 static void VFlip(int *sx, int *sy, int w, int h, int dx, int dy)
85 static void Transpose(int *sx, int *sy, int w, int h, int dx, int dy)
87 VLC_UNUSED( h ); VLC_UNUSED( w );
91 static void AntiTranspose(int *sx, int *sy, int w, int h, int dx, int dy)
96 static void R90(int *sx, int *sy, int w, int h, int dx, int dy)
102 static void R180(int *sx, int *sy, int w, int h, int dx, int dy)
107 static void R270(int *sx, int *sy, int w, int h, int dx, int dy)
113 typedef void (*convert_t)(int *, int *, int, int, int, int);
116 static void Plane8_##f(plane_t *restrict dst, const plane_t *restrict src) \
118 for (int y = 0; y < dst->i_visible_lines; y++) { \
119 for (int x = 0; x < dst->i_visible_pitch; x++) { \
121 (f)(&sx, &sy, dst->i_visible_pitch, dst->i_visible_lines, x, y); \
122 dst->p_pixels[y * dst->i_pitch + x] = \
123 src->p_pixels[sy * src->i_pitch + sx]; \
128 static void Plane16_##f(plane_t *restrict dst, const plane_t *restrict src) \
130 const uint16_t *src_pixels = (const uint16_t *)src->p_pixels; \
131 uint16_t *restrict dst_pixels = (uint16_t *)dst->p_pixels; \
132 unsigned src_width = src->i_pitch / 2; \
133 unsigned dst_width = dst->i_pitch / 2; \
134 unsigned dst_visible_width = dst->i_visible_pitch / 2; \
136 for (int y = 0; y < dst->i_visible_lines; y++) { \
137 for (unsigned x = 0; x < dst_visible_width; x++) { \
139 (f)(&sx, &sy, dst_visible_width, dst->i_visible_lines, x, y); \
140 dst_pixels[y * dst_width + x] = \
141 src_pixels[sy * src_width + sx]; \
146 static void Plane32_##f(plane_t *restrict dst, const plane_t *restrict src) \
148 const uint32_t *src_pixels = (const uint32_t *)src->p_pixels; \
149 uint32_t *restrict dst_pixels = (uint32_t *)dst->p_pixels; \
150 unsigned src_width = src->i_pitch / 4; \
151 unsigned dst_width = dst->i_pitch / 4; \
152 unsigned dst_visible_width = dst->i_visible_pitch / 4; \
154 for (int y = 0; y < dst->i_visible_lines; y++) { \
155 for (unsigned x = 0; x < dst_visible_width; x++) { \
157 (f)(&sx, &sy, dst_visible_width, dst->i_visible_lines, x, y); \
158 dst_pixels[y * dst_width + x] = \
159 src_pixels[sy * src_width + sx]; \
164 static void YUYV_##f(plane_t *restrict dst, const plane_t *restrict src) \
166 unsigned dst_visible_width = dst->i_visible_pitch / 2; \
168 for (int y = 0; y < dst->i_visible_lines; y += 2) { \
169 for (unsigned x = 0; x < dst_visible_width; x+= 2) { \
170 int sx0, sy0, sx1, sy1; \
171 (f)(&sx0, &sy0, dst_visible_width, dst->i_visible_lines, x, y); \
172 (f)(&sx1, &sy1, dst_visible_width, dst->i_visible_lines, \
174 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 0)] = \
175 src->p_pixels[sy0 * src->i_pitch + 2 * sx0]; \
176 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 1)] = \
177 src->p_pixels[sy1 * src->i_pitch + 2 * sx0]; \
178 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 0)] = \
179 src->p_pixels[sy0 * src->i_pitch + 2 * sx1]; \
180 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 1)] = \
181 src->p_pixels[sy1 * src->i_pitch + 2 * sx1]; \
184 (f)(&sx, &sy, dst_visible_width / 2, dst->i_visible_lines / 2, \
186 u = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 1] + \
187 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 1]) / 2; \
188 v = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 3] + \
189 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 3]) / 2; \
190 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 1] = u; \
191 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 3] = v; \
192 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 1] = u; \
193 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 3] = v; \
201 PLANAR(AntiTranspose)
211 void (*plane8) (plane_t *dst, const plane_t *src);
212 void (*plane16)(plane_t *dst, const plane_t *src);
213 void (*plane32)(plane_t *dst, const plane_t *src);
214 void (*yuyv)(plane_t *dst, const plane_t *src);
215 } transform_description_t;
217 #define DESC(str, rotated, f, invf) \
218 { str, rotated, f, invf, Plane8_##f, Plane16_##f, Plane32_##f, YUYV_##f }
220 static const transform_description_t descriptions[] = {
221 DESC("90", true, R90, R270),
222 DESC("180", false, R180, R180),
223 DESC("270", true, R270, R90),
224 DESC("hflip", false, HFlip, HFlip),
225 DESC("vflip", false, VFlip, VFlip),
226 DESC("transpose", true, Transpose, Transpose),
227 DESC("antitranspose", true, AntiTranspose, AntiTranspose),
230 static const size_t n_transforms =
231 sizeof (descriptions) / sizeof (descriptions[0]);
233 struct filter_sys_t {
234 const vlc_chroma_description_t *chroma;
235 void (*plane)(plane_t *, const plane_t *);
239 static picture_t *Filter(filter_t *filter, picture_t *src)
241 filter_sys_t *sys = filter->p_sys;
243 picture_t *dst = filter_NewPicture(filter);
245 picture_Release(src);
249 const vlc_chroma_description_t *chroma = sys->chroma;
250 for (unsigned i = 0; i < chroma->plane_count; i++)
251 sys->plane(&dst->p[i], &src->p[i]);
253 picture_CopyProperties(dst, src);
254 picture_Release(src);
258 static int Mouse(filter_t *filter, vlc_mouse_t *mouse,
259 const vlc_mouse_t *mold, const vlc_mouse_t *mnew)
263 const video_format_t *fmt = &filter->fmt_out.video;
264 const filter_sys_t *sys = filter->p_sys;
267 sys->convert(&mouse->i_x, &mouse->i_y,
268 fmt->i_visible_width, fmt->i_visible_height,
269 mouse->i_x, mouse->i_y);
273 static int Open(vlc_object_t *object)
275 filter_t *filter = (filter_t *)object;
276 const video_format_t *src = &filter->fmt_in.video;
277 video_format_t *dst = &filter->fmt_out.video;
279 const vlc_chroma_description_t *chroma =
280 vlc_fourcc_GetChromaDescription(src->i_chroma);
284 filter_sys_t *sys = malloc(sizeof(*sys));
288 sys->chroma = chroma;
290 char *type_name = var_InheritString(filter, CFG_PREFIX"type");
291 const transform_description_t *dsc = NULL;
293 for (size_t i = 0; i < n_transforms; i++)
294 if (type_name && !strcmp(descriptions[i].name, type_name)) {
295 dsc = &descriptions[i];
299 dsc = &descriptions[0];
300 msg_Warn(filter, "No valid transform mode provided, using '%s'",
306 switch (chroma->pixel_size) {
308 sys->plane = dsc->plane8;
311 sys->plane = dsc->plane16;
314 sys->plane = dsc->plane32;
317 msg_Err(filter, "Unsupported pixel size %u (chroma %4.4s)",
318 chroma->pixel_size, (char *)&src->i_chroma);
322 sys->convert = dsc->convert;
323 if (dsc->is_rotated) {
324 for (unsigned i = 0; i < chroma->plane_count; i++) {
325 if (chroma->p[i].w.num * chroma->p[i].h.den
326 != chroma->p[i].h.num * chroma->p[i].w.den) {
327 msg_Err(filter, "Format rotation not possible (chroma %4.4s)",
328 (char *)&src->i_chroma); /* I422... */
333 if (!filter->b_allow_fmt_out_change) {
334 msg_Err(filter, "Format change is not allowed");
338 dst->i_width = src->i_height;
339 dst->i_visible_width = src->i_visible_height;
340 dst->i_height = src->i_width;
341 dst->i_visible_height = src->i_visible_width;
342 dst->i_sar_num = src->i_sar_den;
343 dst->i_sar_den = src->i_sar_num;
346 /* Deal with weird packed formats */
347 switch (src->i_chroma) {
350 sys->plane = dsc->is_rotated ? dsc->yuyv : dsc->plane32;
354 if (dsc->is_rotated) {
355 msg_Err(filter, "Format rotation not possible (chroma %4.4s)",
356 (char *)&src->i_chroma);
359 sys->plane = dsc->plane32; /* 32-bits, not 16-bits! */
366 dst->i_x_offset = INT_MAX;
367 dst->i_y_offset = INT_MAX;
368 for (int i = 0; i < 2; i++) {
370 dsc->iconvert(&tx, &ty, src->i_width, src->i_height,
371 src->i_x_offset + i * (src->i_visible_width - 1),
372 src->i_y_offset + i * (src->i_visible_height - 1));
373 dst->i_x_offset = __MIN(dst->i_x_offset, (unsigned)(1 + tx));
374 dst->i_y_offset = __MIN(dst->i_y_offset, (unsigned)(1 + ty));
378 filter->pf_video_filter = Filter;
379 filter->pf_video_mouse = Mouse;
386 static void Close(vlc_object_t *object)
388 filter_t *filter = (filter_t *)object;
389 filter_sys_t *sys = filter->p_sys;