1 /*****************************************************************************
2 * mirror.c : Mirror video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
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 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include "filter_picture.h"
39 /*****************************************************************************
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 /*****************************************************************************
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-"
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, NULL, ORIENTATION_TEXT,
85 ORIENTATION_LONGTEXT, false )
86 change_integer_list( pi_orientation_values,
87 ppsz_orientation_descriptions, NULL )
88 add_integer( CFG_PREFIX "direction", 0, NULL, DIRECTION_TEXT,
89 DIRECTION_LONGTEXT, false )
90 change_integer_list( pi_direction_values, ppsz_direction_descriptions,
92 set_callbacks( Create, Destroy )
95 /*****************************************************************************
97 *****************************************************************************/
98 static int FilterCallback( vlc_object_t *, char const *,
99 vlc_value_t, vlc_value_t, void * );
101 /*****************************************************************************
102 * filter_sys_t: adjust filter method descriptor
103 *****************************************************************************/
111 /*****************************************************************************
112 * Create: allocates Mirror video thread output method
113 *****************************************************************************
114 * This function allocates and initializes a Mirror vout method.
115 *****************************************************************************/
116 static int Create( vlc_object_t *p_this )
118 filter_t *p_filter = (filter_t *)p_this;
121 switch( p_filter->fmt_in.video.i_chroma )
123 CASE_PLANAR_YUV_SQUARE
127 case VLC_CODEC_RGB24:
128 case VLC_CODEC_RGB32:
132 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
133 (char*)&(p_filter->fmt_in.video.i_chroma) );
137 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
139 msg_Err( p_filter, "Input and output chromas don't match" );
143 /* Allocate structure */
144 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
145 if( p_filter->p_sys == NULL )
148 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
150 p_sys->i_split = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" );
151 p_sys->i_direction = var_CreateGetIntegerCommand( p_filter,
152 CFG_PREFIX "direction" );
154 vlc_mutex_init( &p_sys->lock );
156 var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, NULL );
157 var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, NULL );
159 p_filter->pf_video_filter = Filter;
164 /*****************************************************************************
165 * Destroy: destroy Mirror video thread output method
166 *****************************************************************************
167 * Terminate an output method created by MirrorCreateOutputMethod
168 *****************************************************************************/
169 static void Destroy( vlc_object_t *p_this )
171 filter_t *p_filter = (filter_t *)p_this;
173 var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, NULL );
174 var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, NULL );
176 vlc_mutex_destroy( &p_filter->p_sys->lock );
177 free( p_filter->p_sys );
180 /*****************************************************************************
181 * Render: displays previously rendered output
182 *****************************************************************************
183 * This function send the currently rendered image to Mirror image, waits
184 * until it is displayed and switch the two rendering buffers, preparing next
186 *****************************************************************************/
187 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
190 bool b_vertical_split, b_left_to_right;
193 if( !p_pic ) return NULL;
195 filter_sys_t *p_sys = p_filter->p_sys;
196 vlc_mutex_lock( &p_sys->lock );
197 b_vertical_split = p_sys->i_split == 0 ? true : false;
198 b_left_to_right = p_sys->i_direction == 0 ? true : false;
199 vlc_mutex_unlock( &p_sys->lock );
201 p_outpic = filter_NewPicture( p_filter );
204 msg_Warn( p_filter, "can't get output picture" );
205 picture_Release( p_pic );
209 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
211 if ( b_vertical_split )
212 VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
214 HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
217 return CopyInfoAndRelease( p_outpic, p_pic );
220 /*****************************************************************************
221 * VerticalMirror: Mirrors vertically image
222 *****************************************************************************
223 * This function is a simple delegate to concrete function for vertical
224 * mirroring depending on the input format.
225 *****************************************************************************/
226 static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
227 bool b_left_to_right )
229 switch( p_pic->format.i_chroma )
231 CASE_PLANAR_YUV_SQUARE
232 PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
236 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
241 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
244 case VLC_CODEC_RGB24:
245 RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
247 case VLC_CODEC_RGB32:
248 RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
255 /*****************************************************************************
256 * PlanarVerticalMirror: Mirrors vertically image byte by byte
257 *****************************************************************************
258 * This function mirrors image vertically. It iterates for all lines in
259 * image and for every line, it mirrors byte for byte if needed.
260 * This function works for planar formats only.
261 *****************************************************************************/
262 static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
263 int i_plane, bool b_left_to_right )
265 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
267 p_in = p_pic->p[i_plane].p_pixels;
268 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
269 * p_pic->p[i_plane].i_pitch;
270 p_out = p_outpic->p[i_plane].p_pixels;
272 while( p_in < p_in_end ) {
274 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
275 while( p_in < p_line_end )
277 /* are we in the left part of the line */
278 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
280 if ( b_left_to_right )
283 *p_out = *( p_line_end - ( p_in - p_line_start ) );
287 if ( b_left_to_right )
288 *p_out = *( p_line_start + ( p_line_end - p_in ) );
295 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
296 p_out += p_outpic->p[i_plane].i_pitch
297 - p_outpic->p[i_plane].i_visible_pitch;
301 /*****************************************************************************
302 * YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
303 *****************************************************************************
304 * This function mirrors image vertically. It iterates for all lines in
305 * image and for every line, it iterates for 4-byte chucks, properly mirroring
306 * them vertically (swapping Y components and keeping Cb and Cr components).
307 * This function works only for YUV422 packed formats.
308 *****************************************************************************/
309 static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
310 int i_plane, bool b_left_to_right,
313 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
315 p_in = p_pic->p[i_plane].p_pixels;
316 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
317 * p_pic->p[i_plane].i_pitch;
318 p_out = p_outpic->p[i_plane].p_pixels;
320 while( p_in < p_in_end )
323 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
324 while( p_in < p_line_end )
326 /* are we in the left part of the line */
327 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
329 if ( b_left_to_right )
338 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
339 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
346 if ( b_left_to_right )
348 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
349 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
362 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
363 p_out += p_outpic->p[i_plane].i_pitch
364 - p_outpic->p[i_plane].i_visible_pitch;
368 /*****************************************************************************
369 * YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
370 *****************************************************************************
371 * This function mirrors two consecutive pixels of 4 byte size. Depending of
372 * position of Y components (b_y_is_odd is true if Y components are first and
373 * third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
374 * component positions are preserved.
375 *****************************************************************************/
376 static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
381 /* swap Y components */
382 *p_dst = *( p_src + 2 );
383 *( p_dst + 2 ) = *p_src;
384 /* copy Cb and Cr components */
385 *( p_dst + 1 ) = *( p_src + 1 );
386 *( p_dst + 3 ) = *( p_src + 3 );
389 /* swap Y components */
390 *( p_dst + 1 )= *( p_src + 3 );
391 *( p_dst + 3 ) = *( p_src + 1);
392 /* copy Cb and Cr components */
393 *p_dst = *( p_src + 2 );
394 *( p_dst + 2 ) = *p_src;
398 /*****************************************************************************
399 * RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
400 *****************************************************************************
401 * This function mirrors image vertically. It iterates for all lines in
402 * image and for every line, it iterates for 3-byte chunks.
403 * This function works only for RV24 formats.
404 *****************************************************************************/
405 static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
406 int i_plane, bool b_left_to_right )
408 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
410 p_in = p_pic->p[i_plane].p_pixels;
411 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
412 * p_pic->p[i_plane].i_pitch;
413 p_out = p_outpic->p[i_plane].p_pixels;
415 while( p_in < p_in_end )
418 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
419 while( p_in < p_line_end )
421 /* are we in the left part of the line */
422 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
424 if ( b_left_to_right )
432 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
434 *p_out++ = *p_pixel++;
435 *p_out++ = *p_pixel++;
436 *p_out++ = *p_pixel++;
441 if ( b_left_to_right )
443 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
445 *p_out++ = *p_pixel++;
446 *p_out++ = *p_pixel++;
447 *p_out++ = *p_pixel++;
457 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
458 p_out += p_outpic->p[i_plane].i_pitch
459 - p_outpic->p[i_plane].i_visible_pitch;
463 /*****************************************************************************
464 * RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
465 *****************************************************************************
466 * This function mirrors image vertically. It iterates for all lines in
467 * image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
468 * This function works only for RV32 formats.
469 *****************************************************************************/
470 static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
471 int i_plane, bool b_left_to_right )
473 uint8_t *p_in, *p_in_end, *p_out;
475 p_in = p_pic->p[i_plane].p_pixels;
476 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
477 * p_pic->p[i_plane].i_pitch;
478 p_out = p_outpic->p[i_plane].p_pixels;
480 while( p_in < p_in_end )
482 uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
483 p_in32 = (uint32_t*) p_in;
484 p_out32 = (uint32_t*) p_out;
485 p_line_start32 = p_in32;
486 p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
488 while( p_in32 < p_line_end32 )
490 /* are we in the left part of the line */
491 if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
493 if ( b_left_to_right )
495 *p_out32++ = *p_in32++;
499 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
501 *p_out++ = *p_pixel32;
506 if ( b_left_to_right )
508 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
510 *p_out++ = *p_pixel32;
514 *p_out32++ = *p_in32++;
518 p_in = (uint8_t*) p_in32;
519 p_out = (uint8_t*) p_out32;
520 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
521 p_out += p_outpic->p[i_plane].i_pitch
522 - p_outpic->p[i_plane].i_visible_pitch;
526 /*****************************************************************************
527 * HorizontalMirror: Mirrors horizontally image byte by byte
528 *****************************************************************************
529 * This function mirrors image horizontally. It iterates for all lines in
530 * image and for every line, determines if it should be copied, and if it does,
531 * finds opposite line in picture and copies current byte from opposite line.
532 * This function works both for planar, packed and RV24 formats.
533 *****************************************************************************/
534 static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
535 bool b_top_to_bottom )
537 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
540 int i_max_lines = p_pic->p[i_plane].i_visible_lines;
542 p_in = p_pic->p[i_plane].p_pixels;
543 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
544 * p_pic->p[i_plane].i_pitch;
545 p_out = p_outpic->p[i_plane].p_pixels;
547 while( p_in < p_in_end )
550 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
551 while( p_in < p_line_end )
553 uint8_t *p_inverse_line;
554 /* are we in the upper part of the picture */
555 if ( i_curr_line < i_max_lines/2 )
557 if ( b_top_to_bottom )
563 /* determines line inverse to current line */
564 p_inverse_line = p_pic->p[i_plane].p_pixels +
565 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
566 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
571 if ( b_top_to_bottom )
573 /* determines line inverse to current line */
574 p_inverse_line = p_pic->p[i_plane].p_pixels +
575 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
576 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
587 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
588 p_out += p_outpic->p[i_plane].i_pitch
589 - p_outpic->p[i_plane].i_visible_pitch;
593 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
594 vlc_value_t oldval, vlc_value_t newval, void *p_data )
596 (void)oldval; (void)p_data;
597 filter_t *p_filter = (filter_t*)p_this;
598 filter_sys_t *p_sys = p_filter->p_sys;
600 if( !strcmp( psz_var, CFG_PREFIX "split" ) )
602 vlc_mutex_lock( &p_sys->lock );
603 p_sys->i_split = newval.i_int;
604 vlc_mutex_unlock( &p_sys->lock );
606 else /* CFG_PREFIX "direction" */
608 vlc_mutex_lock( &p_sys->lock );
609 p_sys->i_direction = newval.i_int;
610 vlc_mutex_unlock( &p_sys->lock );