Freetype: mark as _rgb the appropriate options
[vlc.git] / modules / video_filter / mirror.c
blob543ee31f3a0f7c3e97028aa940346e7de978ecfd
1 /*****************************************************************************
2 * mirror.c : Mirror video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
5 * $Id$
7 * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <assert.h>
36 #include <vlc_filter.h>
37 #include "filter_picture.h"
39 /*****************************************************************************
40 * Local prototypes
41 *****************************************************************************/
42 static int Create ( vlc_object_t * );
43 static void Destroy ( vlc_object_t * );
45 static picture_t *Filter( filter_t *, picture_t * );
46 static void VerticalMirror( picture_t *, picture_t *, int plane, bool );
47 static void HorizontalMirror( picture_t *, picture_t *, int, bool );
48 static void PlanarVerticalMirror( picture_t *, picture_t *, int plane, bool );
49 static void YUV422VerticalMirror( picture_t *, picture_t *, int plane, bool, bool );
50 static void RV24VerticalMirror( picture_t *, picture_t *, int plane, bool );
51 static void RV32VerticalMirror( picture_t *, picture_t *, int plane, bool );
53 static void YUV422Mirror2Pixels( uint8_t *, uint8_t *, bool );
55 static const char *const ppsz_filter_options[] = {
56 "split", "direction", NULL
59 /*****************************************************************************
60 * Module descriptor
61 *****************************************************************************/
62 #define ORIENTATION_TEXT N_("Mirror orientation")
63 #define ORIENTATION_LONGTEXT N_("Defines orientation of the mirror splitting. \
64 Can be vertical or horizontal" )
65 static const int pi_orientation_values[] = { 0, 1 };
66 static const char *const ppsz_orientation_descriptions[] = {
67 N_("Vertical"), N_("Horizontal") };
69 #define DIRECTION_TEXT N_("Direction")
70 #define DIRECTION_LONGTEXT N_("Direction of the mirroring" )
71 static const int pi_direction_values[] = { 0, 1 };
72 static const char *const ppsz_direction_descriptions[] = {
73 N_("Left to right/Top to bottom"), N_("Right to left/Bottom to top") };
75 #define CFG_PREFIX "mirror-"
77 vlc_module_begin ()
78 set_description( N_("Mirror video filter") )
79 set_shortname( N_("Mirror video" ))
80 set_help( N_("Splits video in two same parts, like in a mirror") )
81 set_category( CAT_VIDEO )
82 set_subcategory( SUBCAT_VIDEO_VFILTER )
83 set_capability( "video filter2", 0 )
84 add_integer( CFG_PREFIX "split", 0, ORIENTATION_TEXT,
85 ORIENTATION_LONGTEXT, false )
86 change_integer_list( pi_orientation_values,
87 ppsz_orientation_descriptions )
88 add_integer( CFG_PREFIX "direction", 0, DIRECTION_TEXT,
89 DIRECTION_LONGTEXT, false )
90 change_integer_list( pi_direction_values, ppsz_direction_descriptions )
91 set_callbacks( Create, Destroy )
92 vlc_module_end ()
94 /*****************************************************************************
95 * callback prototypes
96 *****************************************************************************/
97 static int FilterCallback( vlc_object_t *, char const *,
98 vlc_value_t, vlc_value_t, void * );
100 /*****************************************************************************
101 * filter_sys_t: adjust filter method descriptor
102 *****************************************************************************/
103 struct filter_sys_t
105 int i_split;
106 int i_direction;
107 vlc_mutex_t lock;
110 /*****************************************************************************
111 * Create: allocates Mirror video thread output method
112 *****************************************************************************
113 * This function allocates and initializes a Mirror vout method.
114 *****************************************************************************/
115 static int Create( vlc_object_t *p_this )
117 filter_t *p_filter = (filter_t *)p_this;
118 filter_sys_t *p_sys;
120 switch( p_filter->fmt_in.video.i_chroma )
122 CASE_PLANAR_YUV_SQUARE
123 break;
124 CASE_PACKED_YUV_422
125 break;
126 case VLC_CODEC_RGB24:
127 case VLC_CODEC_RGB32:
128 break;
130 default:
131 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
132 (char*)&(p_filter->fmt_in.video.i_chroma) );
133 return VLC_EGENERIC;
136 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
138 msg_Err( p_filter, "Input and output chromas don't match" );
139 return VLC_EGENERIC;
142 /* Allocate structure */
143 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
144 if( p_filter->p_sys == NULL )
145 return VLC_ENOMEM;
147 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
148 p_filter->p_cfg );
149 p_sys->i_split = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" );
150 p_sys->i_direction = var_CreateGetIntegerCommand( p_filter,
151 CFG_PREFIX "direction" );
153 vlc_mutex_init( &p_sys->lock );
155 var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, NULL );
156 var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, NULL );
158 p_filter->pf_video_filter = Filter;
160 return VLC_SUCCESS;
163 /*****************************************************************************
164 * Destroy: destroy Mirror video thread output method
165 *****************************************************************************
166 * Terminate an output method created by MirrorCreateOutputMethod
167 *****************************************************************************/
168 static void Destroy( vlc_object_t *p_this )
170 filter_t *p_filter = (filter_t *)p_this;
172 var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, NULL );
173 var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, NULL );
175 vlc_mutex_destroy( &p_filter->p_sys->lock );
176 free( p_filter->p_sys );
179 /*****************************************************************************
180 * Render: displays previously rendered output
181 *****************************************************************************
182 * This function send the currently rendered image to Mirror image, waits
183 * until it is displayed and switch the two rendering buffers, preparing next
184 * frame.
185 *****************************************************************************/
186 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
188 picture_t *p_outpic;
189 bool b_vertical_split, b_left_to_right;
190 int i_index;
192 if( !p_pic ) return NULL;
194 filter_sys_t *p_sys = p_filter->p_sys;
195 vlc_mutex_lock( &p_sys->lock );
196 b_vertical_split = p_sys->i_split == 0 ? true : false;
197 b_left_to_right = p_sys->i_direction == 0 ? true : false;
198 vlc_mutex_unlock( &p_sys->lock );
200 p_outpic = filter_NewPicture( p_filter );
201 if( !p_outpic )
203 msg_Warn( p_filter, "can't get output picture" );
204 picture_Release( p_pic );
205 return NULL;
208 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
210 if ( b_vertical_split )
211 VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
212 else
213 HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
216 return CopyInfoAndRelease( p_outpic, p_pic );
219 /*****************************************************************************
220 * VerticalMirror: Mirrors vertically image
221 *****************************************************************************
222 * This function is a simple delegate to concrete function for vertical
223 * mirroring depending on the input format.
224 *****************************************************************************/
225 static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
226 bool b_left_to_right )
228 switch( p_pic->format.i_chroma )
230 CASE_PLANAR_YUV_SQUARE
231 PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
232 break;
233 case VLC_CODEC_YUYV:
234 case VLC_CODEC_YVYU:
235 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
236 true );
237 break;
238 case VLC_CODEC_UYVY:
239 case VLC_CODEC_CYUV:
240 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
241 false );
242 break;
243 case VLC_CODEC_RGB24:
244 RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
245 break;
246 case VLC_CODEC_RGB32:
247 RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
248 break;
249 default:
250 assert( false );
254 /*****************************************************************************
255 * PlanarVerticalMirror: Mirrors vertically image byte by byte
256 *****************************************************************************
257 * This function mirrors image vertically. It iterates for all lines in
258 * image and for every line, it mirrors byte for byte if needed.
259 * This function works for planar formats only.
260 *****************************************************************************/
261 static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
262 int i_plane, bool b_left_to_right )
264 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
266 p_in = p_pic->p[i_plane].p_pixels;
267 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
268 * p_pic->p[i_plane].i_pitch;
269 p_out = p_outpic->p[i_plane].p_pixels;
271 while( p_in < p_in_end ) {
272 p_line_start = p_in;
273 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
274 while( p_in < p_line_end )
276 /* are we in the left part of the line */
277 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
279 if ( b_left_to_right )
280 *p_out = *p_in;
281 else
282 *p_out = *( p_line_end - ( p_in - p_line_start ) );
284 else
286 if ( b_left_to_right )
287 *p_out = *( p_line_start + ( p_line_end - p_in ) );
288 else
289 *p_out = *p_in;
291 p_in++;
292 p_out++;
294 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
295 p_out += p_outpic->p[i_plane].i_pitch
296 - p_outpic->p[i_plane].i_visible_pitch;
300 /*****************************************************************************
301 * YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
302 *****************************************************************************
303 * This function mirrors image vertically. It iterates for all lines in
304 * image and for every line, it iterates for 4-byte chucks, properly mirroring
305 * them vertically (swapping Y components and keeping Cb and Cr components).
306 * This function works only for YUV422 packed formats.
307 *****************************************************************************/
308 static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
309 int i_plane, bool b_left_to_right,
310 bool b_y_is_odd )
312 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
314 p_in = p_pic->p[i_plane].p_pixels;
315 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
316 * p_pic->p[i_plane].i_pitch;
317 p_out = p_outpic->p[i_plane].p_pixels;
319 while( p_in < p_in_end )
321 p_line_start = p_in;
322 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
323 while( p_in < p_line_end )
325 /* are we in the left part of the line */
326 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
328 if ( b_left_to_right )
330 *p_out++ = *p_in++;
331 *p_out++ = *p_in++;
332 *p_out++ = *p_in++;
333 *p_out++ = *p_in++;
335 else
337 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
338 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
339 p_in += 4;
340 p_out += 4;
343 else
345 if ( b_left_to_right )
347 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
348 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
349 p_in += 4;
350 p_out += 4;
352 else
354 *p_out++ = *p_in++;
355 *p_out++ = *p_in++;
356 *p_out++ = *p_in++;
357 *p_out++ = *p_in++;
361 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
362 p_out += p_outpic->p[i_plane].i_pitch
363 - p_outpic->p[i_plane].i_visible_pitch;
367 /*****************************************************************************
368 * YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
369 *****************************************************************************
370 * This function mirrors two consecutive pixels of 4 byte size. Depending of
371 * position of Y components (b_y_is_odd is true if Y components are first and
372 * third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
373 * component positions are preserved.
374 *****************************************************************************/
375 static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
376 bool b_y_is_odd )
378 if ( b_y_is_odd )
380 /* swap Y components */
381 *p_dst = *( p_src + 2 );
382 *( p_dst + 2 ) = *p_src;
383 /* copy Cb and Cr components */
384 *( p_dst + 1 ) = *( p_src + 1 );
385 *( p_dst + 3 ) = *( p_src + 3 );
387 else{
388 /* swap Y components */
389 *( p_dst + 1 )= *( p_src + 3 );
390 *( p_dst + 3 ) = *( p_src + 1);
391 /* copy Cb and Cr components */
392 *p_dst = *( p_src + 2 );
393 *( p_dst + 2 ) = *p_src;
397 /*****************************************************************************
398 * RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
399 *****************************************************************************
400 * This function mirrors image vertically. It iterates for all lines in
401 * image and for every line, it iterates for 3-byte chunks.
402 * This function works only for RV24 formats.
403 *****************************************************************************/
404 static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
405 int i_plane, bool b_left_to_right )
407 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
409 p_in = p_pic->p[i_plane].p_pixels;
410 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
411 * p_pic->p[i_plane].i_pitch;
412 p_out = p_outpic->p[i_plane].p_pixels;
414 while( p_in < p_in_end )
416 p_line_start = p_in;
417 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
418 while( p_in < p_line_end )
420 /* are we in the left part of the line */
421 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
423 if ( b_left_to_right )
425 *p_out++ = *p_in++;
426 *p_out++ = *p_in++;
427 *p_out++ = *p_in++;
429 else
431 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
432 p_in += 3;
433 *p_out++ = *p_pixel++;
434 *p_out++ = *p_pixel++;
435 *p_out++ = *p_pixel++;
438 else
440 if ( b_left_to_right )
442 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
443 p_in += 3;
444 *p_out++ = *p_pixel++;
445 *p_out++ = *p_pixel++;
446 *p_out++ = *p_pixel++;
448 else
450 *p_out++ = *p_in++;
451 *p_out++ = *p_in++;
452 *p_out++ = *p_in++;
456 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
457 p_out += p_outpic->p[i_plane].i_pitch
458 - p_outpic->p[i_plane].i_visible_pitch;
462 /*****************************************************************************
463 * RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
464 *****************************************************************************
465 * This function mirrors image vertically. It iterates for all lines in
466 * image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
467 * This function works only for RV32 formats.
468 *****************************************************************************/
469 static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
470 int i_plane, bool b_left_to_right )
472 uint8_t *p_in, *p_in_end, *p_out;
474 p_in = p_pic->p[i_plane].p_pixels;
475 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
476 * p_pic->p[i_plane].i_pitch;
477 p_out = p_outpic->p[i_plane].p_pixels;
479 while( p_in < p_in_end )
481 uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
482 p_in32 = (uint32_t*) p_in;
483 p_out32 = (uint32_t*) p_out;
484 p_line_start32 = p_in32;
485 p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
487 while( p_in32 < p_line_end32 )
489 /* are we in the left part of the line */
490 if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
492 if ( b_left_to_right )
494 *p_out32++ = *p_in32++;
496 else
498 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
499 p_in32++;
500 *p_out++ = *p_pixel32;
503 else
505 if ( b_left_to_right )
507 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
508 p_in32++;
509 *p_out++ = *p_pixel32;
511 else
513 *p_out32++ = *p_in32++;
517 p_in = (uint8_t*) p_in32;
518 p_out = (uint8_t*) p_out32;
519 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
520 p_out += p_outpic->p[i_plane].i_pitch
521 - p_outpic->p[i_plane].i_visible_pitch;
525 /*****************************************************************************
526 * HorizontalMirror: Mirrors horizontally image byte by byte
527 *****************************************************************************
528 * This function mirrors image horizontally. It iterates for all lines in
529 * image and for every line, determines if it should be copied, and if it does,
530 * finds opposite line in picture and copies current byte from opposite line.
531 * This function works both for planar, packed and RV24 formats.
532 *****************************************************************************/
533 static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
534 bool b_top_to_bottom )
536 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
538 int i_curr_line = 0;
539 int i_max_lines = p_pic->p[i_plane].i_visible_lines;
541 p_in = p_pic->p[i_plane].p_pixels;
542 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
543 * p_pic->p[i_plane].i_pitch;
544 p_out = p_outpic->p[i_plane].p_pixels;
546 while( p_in < p_in_end )
548 p_line_start = p_in;
549 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
550 while( p_in < p_line_end )
552 uint8_t *p_inverse_line;
553 /* are we in the upper part of the picture */
554 if ( i_curr_line < i_max_lines/2 )
556 if ( b_top_to_bottom )
558 *p_out = *p_in;
560 else
562 /* determines line inverse to current line */
563 p_inverse_line = p_pic->p[i_plane].p_pixels +
564 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
565 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
568 else
570 if ( b_top_to_bottom )
572 /* determines line inverse to current line */
573 p_inverse_line = p_pic->p[i_plane].p_pixels +
574 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
575 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
577 else
579 *p_out = *p_in;
582 p_in++;
583 p_out++;
585 i_curr_line++;
586 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
587 p_out += p_outpic->p[i_plane].i_pitch
588 - p_outpic->p[i_plane].i_visible_pitch;
592 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
593 vlc_value_t oldval, vlc_value_t newval, void *p_data )
595 (void)oldval; (void)p_data;
596 filter_t *p_filter = (filter_t*)p_this;
597 filter_sys_t *p_sys = p_filter->p_sys;
599 if( !strcmp( psz_var, CFG_PREFIX "split" ) )
601 vlc_mutex_lock( &p_sys->lock );
602 p_sys->i_split = newval.i_int;
603 vlc_mutex_unlock( &p_sys->lock );
605 else /* CFG_PREFIX "direction" */
607 vlc_mutex_lock( &p_sys->lock );
608 p_sys->i_direction = newval.i_int;
609 vlc_mutex_unlock( &p_sys->lock );
612 return VLC_SUCCESS;