qt: playlist: use item title if available
[vlc.git] / modules / video_filter / mirror.c
blobea639dd71147b23cc494b4f02366e7fadb68c064
1 /*****************************************************************************
2 * mirror.c : Mirror video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
6 * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <assert.h>
32 #include <stdatomic.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include <vlc_picture.h>
38 #include "filter_picture.h"
40 /*****************************************************************************
41 * Local prototypes
42 *****************************************************************************/
43 static int Create ( filter_t * );
45 static void VerticalMirror( picture_t *, picture_t *, int plane, bool );
46 static void HorizontalMirror( picture_t *, picture_t *, int, bool );
47 static void PlanarVerticalMirror( picture_t *, picture_t *, int plane, bool );
48 static void YUV422VerticalMirror( picture_t *, picture_t *, int plane, bool, bool );
49 static void RV24VerticalMirror( picture_t *, picture_t *, int plane, bool );
50 static void RV32VerticalMirror( picture_t *, picture_t *, int plane, bool );
52 static void YUV422Mirror2Pixels( uint8_t *, uint8_t *, bool );
53 VIDEO_FILTER_WRAPPER_CLOSE(Filter, Destroy)
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 add_integer( CFG_PREFIX "split", 0, ORIENTATION_TEXT,
84 ORIENTATION_LONGTEXT, false )
85 change_integer_list( pi_orientation_values,
86 ppsz_orientation_descriptions )
87 add_integer( CFG_PREFIX "direction", 0, DIRECTION_TEXT,
88 DIRECTION_LONGTEXT, false )
89 change_integer_list( pi_direction_values, ppsz_direction_descriptions )
90 set_callback_video_filter( Create )
91 vlc_module_end ()
93 /*****************************************************************************
94 * callback prototypes
95 *****************************************************************************/
96 static int FilterCallback( vlc_object_t *, char const *,
97 vlc_value_t, vlc_value_t, void * );
99 /*****************************************************************************
100 * filter_sys_t: adjust filter method descriptor
101 *****************************************************************************/
102 typedef struct
104 atomic_int i_split;
105 atomic_int i_direction;
106 } filter_sys_t;
108 /*****************************************************************************
109 * Create: allocates Mirror video thread output method
110 *****************************************************************************
111 * This function allocates and initializes a Mirror vout method.
112 *****************************************************************************/
113 static int Create( filter_t *p_filter )
115 filter_sys_t *p_sys;
117 switch( p_filter->fmt_in.video.i_chroma )
119 CASE_PLANAR_YUV_SQUARE
120 break;
121 CASE_PACKED_YUV_422
122 break;
123 case VLC_CODEC_RGB24:
124 case VLC_CODEC_RGB32:
125 break;
127 default:
128 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
129 (char*)&(p_filter->fmt_in.video.i_chroma) );
130 return VLC_EGENERIC;
133 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
135 msg_Err( p_filter, "Input and output chromas don't match" );
136 return VLC_EGENERIC;
139 /* Allocate structure */
140 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
141 if( p_filter->p_sys == NULL )
142 return VLC_ENOMEM;
144 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
145 p_filter->p_cfg );
146 atomic_init( &p_sys->i_split,
147 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" ) );
148 atomic_init( &p_sys->i_direction,
149 var_CreateGetIntegerCommand( p_filter,
150 CFG_PREFIX "direction" ) );
152 var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
153 var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
155 p_filter->ops = &Filter_ops;
157 return VLC_SUCCESS;
160 /*****************************************************************************
161 * Destroy: destroy Mirror video thread output method
162 *****************************************************************************
163 * Terminate an output method created by MirrorCreateOutputMethod
164 *****************************************************************************/
165 static void Destroy( filter_t *p_filter )
167 filter_sys_t *p_sys = p_filter->p_sys;
169 var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
170 var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
171 free( p_sys );
174 /*****************************************************************************
175 * Render: displays previously rendered output
176 *****************************************************************************
177 * This function send the currently rendered image to Mirror image, waits
178 * until it is displayed and switch the two rendering buffers, preparing next
179 * frame.
180 *****************************************************************************/
181 static void Filter( filter_t *p_filter, picture_t *p_pic, picture_t *p_outpic )
183 bool b_vertical_split, b_left_to_right;
185 filter_sys_t *p_sys = p_filter->p_sys;
186 b_vertical_split = !atomic_load( &p_sys->i_split );
187 b_left_to_right = !atomic_load( &p_sys->i_direction );
189 for( int i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
191 if ( b_vertical_split )
192 VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
193 else
194 HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
198 /*****************************************************************************
199 * VerticalMirror: Mirrors vertically image
200 *****************************************************************************
201 * This function is a simple delegate to concrete function for vertical
202 * mirroring depending on the input format.
203 *****************************************************************************/
204 static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
205 bool b_left_to_right )
207 switch( p_pic->format.i_chroma )
209 CASE_PLANAR_YUV_SQUARE
210 PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
211 break;
212 case VLC_CODEC_YUYV:
213 case VLC_CODEC_YVYU:
214 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
215 true );
216 break;
217 case VLC_CODEC_UYVY:
218 break;
219 case VLC_CODEC_RGB24:
220 RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
221 break;
222 case VLC_CODEC_RGB32:
223 RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
224 break;
225 default:
226 vlc_assert_unreachable();
230 /*****************************************************************************
231 * PlanarVerticalMirror: Mirrors vertically image byte by byte
232 *****************************************************************************
233 * This function mirrors image vertically. It iterates for all lines in
234 * image and for every line, it mirrors byte for byte if needed.
235 * This function works for planar formats only.
236 *****************************************************************************/
237 static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
238 int i_plane, bool b_left_to_right )
240 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
242 p_in = p_pic->p[i_plane].p_pixels;
243 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
244 * p_pic->p[i_plane].i_pitch;
245 p_out = p_outpic->p[i_plane].p_pixels;
247 while( p_in < p_in_end ) {
248 p_line_start = p_in;
249 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
250 while( p_in < p_line_end )
252 /* are we in the left part of the line */
253 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
255 if ( b_left_to_right )
256 *p_out = *p_in;
257 else
258 *p_out = *( p_line_end - ( p_in - p_line_start ) );
260 else
262 if ( b_left_to_right )
263 *p_out = *( p_line_start + ( p_line_end - p_in ) );
264 else
265 *p_out = *p_in;
267 p_in++;
268 p_out++;
270 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
271 p_out += p_outpic->p[i_plane].i_pitch
272 - p_outpic->p[i_plane].i_visible_pitch;
276 /*****************************************************************************
277 * YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
278 *****************************************************************************
279 * This function mirrors image vertically. It iterates for all lines in
280 * image and for every line, iterates for 4-byte chucks, properly mirroring
281 * them vertically (swapping Y components and keeping Cb and Cr components).
282 * This function works only for YUV422 packed formats.
283 *****************************************************************************/
284 static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
285 int i_plane, bool b_left_to_right,
286 bool b_y_is_odd )
288 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
290 p_in = p_pic->p[i_plane].p_pixels;
291 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
292 * p_pic->p[i_plane].i_pitch;
293 p_out = p_outpic->p[i_plane].p_pixels;
295 while( p_in < p_in_end )
297 p_line_start = p_in;
298 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
299 while( p_in < p_line_end )
301 /* are we in the left part of the line */
302 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
304 if ( b_left_to_right )
306 *p_out++ = *p_in++;
307 *p_out++ = *p_in++;
308 *p_out++ = *p_in++;
309 *p_out++ = *p_in++;
311 else
313 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
314 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
315 p_in += 4;
316 p_out += 4;
319 else
321 if ( b_left_to_right )
323 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
324 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
325 p_in += 4;
326 p_out += 4;
328 else
330 *p_out++ = *p_in++;
331 *p_out++ = *p_in++;
332 *p_out++ = *p_in++;
333 *p_out++ = *p_in++;
337 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
338 p_out += p_outpic->p[i_plane].i_pitch
339 - p_outpic->p[i_plane].i_visible_pitch;
343 /*****************************************************************************
344 * YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
345 *****************************************************************************
346 * This function mirrors two consecutive pixels of 4 byte size. Depending of
347 * position of Y components (b_y_is_odd is true if Y components are first and
348 * third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
349 * component positions are preserved.
350 *****************************************************************************/
351 static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
352 bool b_y_is_odd )
354 if ( b_y_is_odd )
356 /* swap Y components */
357 *p_dst = *( p_src + 2 );
358 *( p_dst + 2 ) = *p_src;
359 /* copy Cb and Cr components */
360 *( p_dst + 1 ) = *( p_src + 1 );
361 *( p_dst + 3 ) = *( p_src + 3 );
363 else{
364 /* swap Y components */
365 *( p_dst + 1 )= *( p_src + 3 );
366 *( p_dst + 3 ) = *( p_src + 1);
367 /* copy Cb and Cr components */
368 *p_dst = *( p_src + 2 );
369 *( p_dst + 2 ) = *p_src;
373 /*****************************************************************************
374 * RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
375 *****************************************************************************
376 * This function mirrors image vertically. It iterates for all lines in
377 * image and for every line, it iterates for 3-byte chunks.
378 * This function works only for RV24 formats.
379 *****************************************************************************/
380 static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
381 int i_plane, bool b_left_to_right )
383 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
385 p_in = p_pic->p[i_plane].p_pixels;
386 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
387 * p_pic->p[i_plane].i_pitch;
388 p_out = p_outpic->p[i_plane].p_pixels;
390 while( p_in < p_in_end )
392 p_line_start = p_in;
393 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
394 while( p_in < p_line_end )
396 /* are we in the left part of the line */
397 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
399 if ( b_left_to_right )
401 *p_out++ = *p_in++;
402 *p_out++ = *p_in++;
403 *p_out++ = *p_in++;
405 else
407 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
408 p_in += 3;
409 *p_out++ = *p_pixel++;
410 *p_out++ = *p_pixel++;
411 *p_out++ = *p_pixel++;
414 else
416 if ( b_left_to_right )
418 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
419 p_in += 3;
420 *p_out++ = *p_pixel++;
421 *p_out++ = *p_pixel++;
422 *p_out++ = *p_pixel++;
424 else
426 *p_out++ = *p_in++;
427 *p_out++ = *p_in++;
428 *p_out++ = *p_in++;
432 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
433 p_out += p_outpic->p[i_plane].i_pitch
434 - p_outpic->p[i_plane].i_visible_pitch;
438 /*****************************************************************************
439 * RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
440 *****************************************************************************
441 * This function mirrors image vertically. It iterates for all lines in
442 * image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
443 * This function works only for RV32 formats.
444 *****************************************************************************/
445 static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
446 int i_plane, bool b_left_to_right )
448 uint8_t *p_in, *p_in_end, *p_out;
450 p_in = p_pic->p[i_plane].p_pixels;
451 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
452 * p_pic->p[i_plane].i_pitch;
453 p_out = p_outpic->p[i_plane].p_pixels;
455 while( p_in < p_in_end )
457 uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
458 p_in32 = (uint32_t*) p_in;
459 p_out32 = (uint32_t*) p_out;
460 p_line_start32 = p_in32;
461 p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
463 while( p_in32 < p_line_end32 )
465 /* are we in the left part of the line */
466 if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
468 if ( b_left_to_right )
470 *p_out32++ = *p_in32++;
472 else
474 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
475 p_in32++;
476 *p_out++ = *p_pixel32;
479 else
481 if ( b_left_to_right )
483 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
484 p_in32++;
485 *p_out++ = *p_pixel32;
487 else
489 *p_out32++ = *p_in32++;
493 p_in = (uint8_t*) p_in32;
494 p_out = (uint8_t*) p_out32;
495 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
496 p_out += p_outpic->p[i_plane].i_pitch
497 - p_outpic->p[i_plane].i_visible_pitch;
501 /*****************************************************************************
502 * HorizontalMirror: Mirrors horizontally image byte by byte
503 *****************************************************************************
504 * This function mirrors image horizontally. It iterates for all lines in
505 * image and for every line, determines if it should be copied, and if it does,
506 * finds opposite line in picture and copies current byte from opposite line.
507 * This function works both for planar, packed and RV24 formats.
508 *****************************************************************************/
509 static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
510 bool b_top_to_bottom )
512 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
514 int i_curr_line = 0;
515 int i_max_lines = p_pic->p[i_plane].i_visible_lines;
517 p_in = p_pic->p[i_plane].p_pixels;
518 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
519 * p_pic->p[i_plane].i_pitch;
520 p_out = p_outpic->p[i_plane].p_pixels;
522 while( p_in < p_in_end )
524 p_line_start = p_in;
525 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
526 while( p_in < p_line_end )
528 uint8_t *p_inverse_line;
529 /* are we in the upper part of the picture */
530 if ( i_curr_line < i_max_lines/2 )
532 if ( b_top_to_bottom )
534 *p_out = *p_in;
536 else
538 /* determines line inverse to current line */
539 p_inverse_line = p_pic->p[i_plane].p_pixels +
540 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
541 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
544 else
546 if ( b_top_to_bottom )
548 /* determines line inverse to current line */
549 p_inverse_line = p_pic->p[i_plane].p_pixels +
550 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
551 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
553 else
555 *p_out = *p_in;
558 p_in++;
559 p_out++;
561 i_curr_line++;
562 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
563 p_out += p_outpic->p[i_plane].i_pitch
564 - p_outpic->p[i_plane].i_visible_pitch;
568 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
569 vlc_value_t oldval, vlc_value_t newval, void *p_data )
571 (void) p_this; (void)oldval;
572 filter_sys_t *p_sys = p_data;
574 if( !strcmp( psz_var, CFG_PREFIX "split" ) )
575 atomic_store( &p_sys->i_split, newval.i_int );
576 else /* CFG_PREFIX "direction" */
577 atomic_store( &p_sys->i_direction, newval.i_int );
579 return VLC_SUCCESS;