demux/playlist: xspf: only use text-elements inside current tag
[vlc.git] / modules / video_filter / transform.c
blob7c88f234ef8a9775cf72dd07ec4da78d2b525b70
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 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 #include <limits.h>
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
38 #include <vlc_mouse.h>
39 #include <vlc_picture.h>
41 /*****************************************************************************
42 * Module descriptor
43 *****************************************************************************/
44 static int Open (vlc_object_t *);
45 static void Close(vlc_object_t *);
47 #define CFG_PREFIX "transform-"
49 #define TYPE_TEXT N_("Transform type")
50 static const char * const type_list[] = { "90", "180", "270",
51 "hflip", "vflip", "transpose", "antitranspose" };
52 static const char * const type_list_text[] = { N_("Rotate by 90 degrees"),
53 N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
54 N_("Flip horizontally"), N_("Flip vertically"),
55 N_("Transpose"), N_("Anti-transpose") };
57 vlc_module_begin()
58 set_description(N_("Video transformation filter"))
59 set_shortname(N_("Transformation"))
60 set_help(N_("Rotate or flip the video"))
61 set_capability("video filter", 0)
62 set_category(CAT_VIDEO)
63 set_subcategory(SUBCAT_VIDEO_VFILTER)
65 add_string(CFG_PREFIX "type", "90", TYPE_TEXT, TYPE_TEXT, false)
66 change_string_list(type_list, type_list_text)
67 change_safe()
69 add_shortcut("transform")
70 set_callbacks(Open, Close)
71 vlc_module_end()
73 /*****************************************************************************
74 * Local prototypes
75 *****************************************************************************/
76 static void HFlip(int *sx, int *sy, int w, int h, int dx, int dy)
78 VLC_UNUSED( h );
79 *sx = w - 1 - dx;
80 *sy = dy;
82 static void VFlip(int *sx, int *sy, int w, int h, int dx, int dy)
84 VLC_UNUSED( w );
85 *sx = dx;
86 *sy = h - 1 - dy;
88 static void Transpose(int *sx, int *sy, int w, int h, int dx, int dy)
90 VLC_UNUSED( h ); VLC_UNUSED( w );
91 *sx = dy;
92 *sy = dx;
94 static void AntiTranspose(int *sx, int *sy, int w, int h, int dx, int dy)
96 *sx = h - 1 - dy;
97 *sy = w - 1 - dx;
99 static void R90(int *sx, int *sy, int w, int h, int dx, int dy)
101 VLC_UNUSED( h );
102 *sx = dy;
103 *sy = w - 1 - dx;
105 static void R180(int *sx, int *sy, int w, int h, int dx, int dy)
107 *sx = w - 1 - dx;
108 *sy = h - 1 - dy;
110 static void R270(int *sx, int *sy, int w, int h, int dx, int dy)
112 VLC_UNUSED( w );
113 *sx = h - 1 - dy;
114 *sy = dx;
116 typedef void (*convert_t)(int *, int *, int, int, int, int);
118 #define PLANE(f,bits) \
119 static void Plane##bits##_##f(plane_t *restrict dst, const plane_t *restrict src) \
121 const uint##bits##_t *src_pixels = (const void *)src->p_pixels; \
122 uint##bits##_t *restrict dst_pixels = (void *)dst->p_pixels; \
123 const unsigned src_width = src->i_pitch / sizeof (*src_pixels); \
124 const unsigned dst_width = dst->i_pitch / sizeof (*dst_pixels); \
125 const unsigned dst_visible_width = dst->i_visible_pitch / sizeof (*dst_pixels); \
127 for (int y = 0; y < dst->i_visible_lines; y++) { \
128 for (unsigned x = 0; x < dst_visible_width; x++) { \
129 int sx, sy; \
130 (f)(&sx, &sy, dst_visible_width, dst->i_visible_lines, x, y); \
131 dst_pixels[y * dst_width + x] = \
132 src_pixels[sy * src_width + sx]; \
137 static void Plane_VFlip(plane_t *restrict dst, const plane_t *restrict src)
139 const uint8_t *src_pixels = src->p_pixels;
140 uint8_t *restrict dst_pixels = dst->p_pixels;
142 dst_pixels += dst->i_pitch * dst->i_visible_lines;
143 for (int y = 0; y < dst->i_visible_lines; y++) {
144 dst_pixels -= dst->i_pitch;
145 memcpy(dst_pixels, src_pixels, dst->i_visible_pitch);
146 src_pixels += src->i_pitch;
150 #define I422(f) \
151 static void Plane422_##f(plane_t *restrict dst, const plane_t *restrict src) \
153 for (int y = 0; y < dst->i_visible_lines; y += 2) { \
154 for (int x = 0; x < dst->i_visible_pitch; x++) { \
155 int sx, sy, uv; \
156 (f)(&sx, &sy, dst->i_visible_pitch, dst->i_visible_lines / 2, \
157 x, y / 2); \
158 uv = (1 + src->p_pixels[2 * sy * src->i_pitch + sx] + \
159 src->p_pixels[(2 * sy + 1) * src->i_pitch + sx]) / 2; \
160 dst->p_pixels[y * dst->i_pitch + x] = uv; \
161 dst->p_pixels[(y + 1) * dst->i_pitch + x] = uv; \
166 #define YUY2(f) \
167 static void PlaneYUY2_##f(plane_t *restrict dst, const plane_t *restrict src) \
169 unsigned dst_visible_width = dst->i_visible_pitch / 2; \
171 for (int y = 0; y < dst->i_visible_lines; y += 2) { \
172 for (unsigned x = 0; x < dst_visible_width; x+= 2) { \
173 int sx0, sy0, sx1, sy1; \
174 (f)(&sx0, &sy0, dst_visible_width, dst->i_visible_lines, x, y); \
175 (f)(&sx1, &sy1, dst_visible_width, dst->i_visible_lines, \
176 x + 1, y + 1); \
177 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 0)] = \
178 src->p_pixels[sy0 * src->i_pitch + 2 * sx0]; \
179 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * (x + 1)] = \
180 src->p_pixels[sy1 * src->i_pitch + 2 * sx0]; \
181 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 0)] = \
182 src->p_pixels[sy0 * src->i_pitch + 2 * sx1]; \
183 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * (x + 1)] = \
184 src->p_pixels[sy1 * src->i_pitch + 2 * sx1]; \
186 int sx, sy, u, v; \
187 (f)(&sx, &sy, dst_visible_width / 2, dst->i_visible_lines / 2, \
188 x / 2, y / 2); \
189 u = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 1] + \
190 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 1]) / 2; \
191 v = (1 + src->p_pixels[2 * sy * src->i_pitch + 4 * sx + 3] + \
192 src->p_pixels[(2 * sy + 1) * src->i_pitch + 4 * sx + 3]) / 2; \
193 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 1] = u; \
194 dst->p_pixels[(y + 0) * dst->i_pitch + 2 * x + 3] = v; \
195 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 1] = u; \
196 dst->p_pixels[(y + 1) * dst->i_pitch + 2 * x + 3] = v; \
201 #define PLANES(f) \
202 PLANE(f,8) PLANE(f,16) PLANE(f,32)
204 PLANES(HFlip)
205 #define Plane8_VFlip Plane_VFlip
206 #define Plane16_VFlip Plane_VFlip
207 #define Plane32_VFlip Plane_VFlip
208 PLANES(Transpose)
209 PLANES(AntiTranspose)
210 PLANES(R90)
211 PLANES(R180)
212 PLANES(R270)
214 #define Plane422_HFlip Plane16_HFlip
215 #define Plane422_VFlip Plane_VFlip
216 #define Plane422_R180 Plane16_R180
217 I422(Transpose)
218 I422(AntiTranspose)
219 I422(R90)
220 I422(R270)
222 #define PlaneYUY2_HFlip Plane32_HFlip
223 #define PlaneYUY2_VFlip Plane_VFlip
224 #define PlaneYUY2_R180 Plane32_R180
225 YUY2(Transpose)
226 YUY2(AntiTranspose)
227 YUY2(R90)
228 YUY2(R270)
230 typedef struct {
231 char name[16];
232 convert_t convert;
233 convert_t iconvert;
234 video_transform_t operation;
235 void (*plane8) (plane_t *dst, const plane_t *src);
236 void (*plane16)(plane_t *dst, const plane_t *src);
237 void (*plane32)(plane_t *dst, const plane_t *src);
238 void (*i422)(plane_t *dst, const plane_t *src);
239 void (*yuyv)(plane_t *dst, const plane_t *src);
240 } transform_description_t;
242 #define DESC(str, f, invf, op) \
243 { str, f, invf, op, Plane8_##f, Plane16_##f, Plane32_##f, \
244 Plane422_##f, PlaneYUY2_##f }
246 static const transform_description_t descriptions[] = {
247 DESC("90", R90, R270, TRANSFORM_R90),
248 DESC("180", R180, R180, TRANSFORM_R180),
249 DESC("270", R270, R90, TRANSFORM_R270),
250 DESC("hflip", HFlip, HFlip, TRANSFORM_HFLIP),
251 DESC("vflip", VFlip, VFlip, TRANSFORM_VFLIP),
252 DESC("transpose", Transpose, Transpose, TRANSFORM_TRANSPOSE),
253 DESC("antitranspose", AntiTranspose, AntiTranspose, TRANSFORM_ANTI_TRANSPOSE),
256 static bool dsc_is_rotated(const transform_description_t *dsc)
258 return dsc->plane32 != dsc->yuyv;
261 static const size_t n_transforms =
262 sizeof (descriptions) / sizeof (descriptions[0]);
264 struct filter_sys_t {
265 const vlc_chroma_description_t *chroma;
266 void (*plane[PICTURE_PLANE_MAX])(plane_t *, const plane_t *);
267 convert_t convert;
270 static picture_t *Filter(filter_t *filter, picture_t *src)
272 filter_sys_t *sys = filter->p_sys;
274 picture_t *dst = filter_NewPicture(filter);
275 if (!dst) {
276 picture_Release(src);
277 return NULL;
280 const vlc_chroma_description_t *chroma = sys->chroma;
281 for (unsigned i = 0; i < chroma->plane_count; i++)
282 (sys->plane[i])(&dst->p[i], &src->p[i]);
284 picture_CopyProperties(dst, src);
285 picture_Release(src);
286 return dst;
289 static int Mouse(filter_t *filter, vlc_mouse_t *mouse,
290 const vlc_mouse_t *mold, const vlc_mouse_t *mnew)
292 VLC_UNUSED( mold );
294 const video_format_t *fmt = &filter->fmt_out.video;
295 const filter_sys_t *sys = filter->p_sys;
297 *mouse = *mnew;
298 sys->convert(&mouse->i_x, &mouse->i_y,
299 fmt->i_visible_width, fmt->i_visible_height,
300 mouse->i_x, mouse->i_y);
301 return VLC_SUCCESS;
304 static int Open(vlc_object_t *object)
306 filter_t *filter = (filter_t *)object;
307 const video_format_t *src = &filter->fmt_in.video;
308 video_format_t *dst = &filter->fmt_out.video;
310 const vlc_chroma_description_t *chroma =
311 vlc_fourcc_GetChromaDescription(src->i_chroma);
312 if (chroma == NULL)
313 return VLC_EGENERIC;
315 filter_sys_t *sys = malloc(sizeof(*sys));
316 if (!sys)
317 return VLC_ENOMEM;
319 sys->chroma = chroma;
321 static const char *const ppsz_filter_options[] = {
322 "type", NULL
325 config_ChainParse(filter, CFG_PREFIX, ppsz_filter_options,
326 filter->p_cfg);
327 char *type_name = var_InheritString(filter, CFG_PREFIX"type");
328 const transform_description_t *dsc = NULL;
330 for (size_t i = 0; i < n_transforms; i++)
331 if (type_name && !strcmp(descriptions[i].name, type_name)) {
332 dsc = &descriptions[i];
333 break;
335 if (dsc == NULL) {
336 dsc = &descriptions[0];
337 msg_Warn(filter, "No valid transform mode provided, using '%s'",
338 dsc->name);
341 free(type_name);
343 switch (chroma->pixel_size) {
344 case 1:
345 sys->plane[0] = dsc->plane8;
346 break;
347 case 2:
348 sys->plane[0] = dsc->plane16;
349 break;
350 case 4:
351 sys->plane[0] = dsc->plane32;
352 break;
353 default:
354 msg_Err(filter, "Unsupported pixel size %u (chroma %4.4s)",
355 chroma->pixel_size, (char *)&src->i_chroma);
356 goto error;
359 for (unsigned i = 1; i < PICTURE_PLANE_MAX; i++)
360 sys->plane[i] = sys->plane[0];
361 sys->convert = dsc->convert;
363 if (dsc_is_rotated(dsc)) {
364 switch (src->i_chroma) {
365 case VLC_CODEC_I422:
366 case VLC_CODEC_J422:
367 sys->plane[2] = sys->plane[1] = dsc->i422;
368 break;
369 default:
370 for (unsigned i = 0; i < chroma->plane_count; i++) {
371 if (chroma->p[i].w.num * chroma->p[i].h.den
372 != chroma->p[i].h.num * chroma->p[i].w.den) {
373 msg_Err(filter, "Format rotation not possible "
374 "(chroma %4.4s)", (char *)&src->i_chroma);
375 goto error;
382 * Note: we neither compare nor set dst->orientation,
383 * the caller needs to do it manually (user might want
384 * to transform video without changing the orientation).
387 video_format_t src_trans = *src;
388 video_format_TransformBy(&src_trans, dsc->operation);
390 if (!filter->b_allow_fmt_out_change &&
391 (dst->i_width != src_trans.i_width ||
392 dst->i_visible_width != src_trans.i_visible_width ||
393 dst->i_height != src_trans.i_height ||
394 dst->i_visible_height != src_trans.i_visible_height ||
395 dst->i_sar_num != src_trans.i_sar_num ||
396 dst->i_sar_den != src_trans.i_sar_den ||
397 dst->i_x_offset != src_trans.i_x_offset ||
398 dst->i_y_offset != src_trans.i_y_offset)) {
400 msg_Err(filter, "Format change is not allowed");
401 goto error;
403 else if(filter->b_allow_fmt_out_change) {
405 dst->i_width = src_trans.i_width;
406 dst->i_visible_width = src_trans.i_visible_width;
407 dst->i_height = src_trans.i_height;
408 dst->i_visible_height = src_trans.i_visible_height;
409 dst->i_sar_num = src_trans.i_sar_num;
410 dst->i_sar_den = src_trans.i_sar_den;
411 dst->i_x_offset = src_trans.i_x_offset;
412 dst->i_y_offset = src_trans.i_y_offset;
415 /* Deal with weird packed formats */
416 switch (src->i_chroma) {
417 case VLC_CODEC_UYVY:
418 case VLC_CODEC_VYUY:
419 if (dsc_is_rotated(dsc)) {
420 msg_Err(filter, "Format rotation not possible (chroma %4.4s)",
421 (char *)&src->i_chroma);
422 goto error;
424 /* fallthrough */
425 case VLC_CODEC_YUYV:
426 case VLC_CODEC_YVYU:
427 sys->plane[0] = dsc->yuyv; /* 32-bits, not 16-bits! */
428 break;
429 case VLC_CODEC_NV12:
430 case VLC_CODEC_NV21:
431 goto error;
434 filter->p_sys = sys;
435 filter->pf_video_filter = Filter;
436 filter->pf_video_mouse = Mouse;
437 return VLC_SUCCESS;
438 error:
439 free(sys);
440 return VLC_EGENERIC;
443 static void Close(vlc_object_t *object)
445 filter_t *filter = (filter_t *)object;
446 filter_sys_t *sys = filter->p_sys;
448 free(sys);