demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / video_filter / mirror.c
blob719428eabbd81f2297a1b4ba63ea3b37f821e827
1 /*****************************************************************************
2 * mirror.c : Mirror video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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 <assert.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_atomic.h>
37 #include <vlc_filter.h>
38 #include <vlc_picture.h>
39 #include "filter_picture.h"
41 /*****************************************************************************
42 * Local prototypes
43 *****************************************************************************/
44 static int Create ( vlc_object_t * );
45 static void Destroy ( vlc_object_t * );
47 static picture_t *Filter( filter_t *, picture_t * );
48 static void VerticalMirror( picture_t *, picture_t *, int plane, bool );
49 static void HorizontalMirror( picture_t *, picture_t *, int, bool );
50 static void PlanarVerticalMirror( picture_t *, picture_t *, int plane, bool );
51 static void YUV422VerticalMirror( picture_t *, picture_t *, int plane, bool, bool );
52 static void RV24VerticalMirror( picture_t *, picture_t *, int plane, bool );
53 static void RV32VerticalMirror( picture_t *, picture_t *, int plane, bool );
55 static void YUV422Mirror2Pixels( uint8_t *, uint8_t *, bool );
57 static const char *const ppsz_filter_options[] = {
58 "split", "direction", NULL
61 /*****************************************************************************
62 * Module descriptor
63 *****************************************************************************/
64 #define ORIENTATION_TEXT N_("Mirror orientation")
65 #define ORIENTATION_LONGTEXT N_("Defines orientation of the mirror splitting. \
66 Can be vertical or horizontal" )
67 static const int pi_orientation_values[] = { 0, 1 };
68 static const char *const ppsz_orientation_descriptions[] = {
69 N_("Vertical"), N_("Horizontal") };
71 #define DIRECTION_TEXT N_("Direction")
72 #define DIRECTION_LONGTEXT N_("Direction of the mirroring" )
73 static const int pi_direction_values[] = { 0, 1 };
74 static const char *const ppsz_direction_descriptions[] = {
75 N_("Left to right/Top to bottom"), N_("Right to left/Bottom to top") };
77 #define CFG_PREFIX "mirror-"
79 vlc_module_begin ()
80 set_description( N_("Mirror video filter") )
81 set_shortname( N_("Mirror video" ))
82 set_help( N_("Splits video in two same parts, like in a mirror") )
83 set_category( CAT_VIDEO )
84 set_subcategory( SUBCAT_VIDEO_VFILTER )
85 set_capability( "video filter", 0 )
86 add_integer( CFG_PREFIX "split", 0, ORIENTATION_TEXT,
87 ORIENTATION_LONGTEXT, false )
88 change_integer_list( pi_orientation_values,
89 ppsz_orientation_descriptions )
90 add_integer( CFG_PREFIX "direction", 0, DIRECTION_TEXT,
91 DIRECTION_LONGTEXT, false )
92 change_integer_list( pi_direction_values, ppsz_direction_descriptions )
93 set_callbacks( Create, Destroy )
94 vlc_module_end ()
96 /*****************************************************************************
97 * callback prototypes
98 *****************************************************************************/
99 static int FilterCallback( vlc_object_t *, char const *,
100 vlc_value_t, vlc_value_t, void * );
102 /*****************************************************************************
103 * filter_sys_t: adjust filter method descriptor
104 *****************************************************************************/
105 struct filter_sys_t
107 atomic_int i_split;
108 atomic_int i_direction;
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;
119 filter_sys_t *p_sys;
121 switch( p_filter->fmt_in.video.i_chroma )
123 CASE_PLANAR_YUV_SQUARE
124 break;
125 CASE_PACKED_YUV_422
126 break;
127 case VLC_CODEC_RGB24:
128 case VLC_CODEC_RGB32:
129 break;
131 default:
132 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
133 (char*)&(p_filter->fmt_in.video.i_chroma) );
134 return VLC_EGENERIC;
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" );
140 return VLC_EGENERIC;
143 /* Allocate structure */
144 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
145 if( p_filter->p_sys == NULL )
146 return VLC_ENOMEM;
148 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
149 p_filter->p_cfg );
150 atomic_init( &p_sys->i_split,
151 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" ) );
152 atomic_init( &p_sys->i_direction,
153 var_CreateGetIntegerCommand( p_filter,
154 CFG_PREFIX "direction" ) );
156 var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
157 var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
159 p_filter->pf_video_filter = Filter;
161 return VLC_SUCCESS;
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;
172 filter_sys_t *p_sys = p_filter->p_sys;
174 var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
175 var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
176 free( 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;
191 if( !p_pic ) return NULL;
193 filter_sys_t *p_sys = p_filter->p_sys;
194 b_vertical_split = !atomic_load( &p_sys->i_split );
195 b_left_to_right = !atomic_load( &p_sys->i_direction );
197 p_outpic = filter_NewPicture( p_filter );
198 if( !p_outpic )
200 msg_Warn( p_filter, "can't get output picture" );
201 picture_Release( p_pic );
202 return NULL;
205 for( int i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
207 if ( b_vertical_split )
208 VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
209 else
210 HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
213 return CopyInfoAndRelease( p_outpic, p_pic );
216 /*****************************************************************************
217 * VerticalMirror: Mirrors vertically image
218 *****************************************************************************
219 * This function is a simple delegate to concrete function for vertical
220 * mirroring depending on the input format.
221 *****************************************************************************/
222 static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
223 bool b_left_to_right )
225 switch( p_pic->format.i_chroma )
227 CASE_PLANAR_YUV_SQUARE
228 PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
229 break;
230 case VLC_CODEC_YUYV:
231 case VLC_CODEC_YVYU:
232 YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
233 true );
234 break;
235 case VLC_CODEC_UYVY:
236 break;
237 case VLC_CODEC_RGB24:
238 RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
239 break;
240 case VLC_CODEC_RGB32:
241 RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
242 break;
243 default:
244 vlc_assert_unreachable();
248 /*****************************************************************************
249 * PlanarVerticalMirror: Mirrors vertically image byte by byte
250 *****************************************************************************
251 * This function mirrors image vertically. It iterates for all lines in
252 * image and for every line, it mirrors byte for byte if needed.
253 * This function works for planar formats only.
254 *****************************************************************************/
255 static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
256 int i_plane, bool b_left_to_right )
258 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
260 p_in = p_pic->p[i_plane].p_pixels;
261 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
262 * p_pic->p[i_plane].i_pitch;
263 p_out = p_outpic->p[i_plane].p_pixels;
265 while( p_in < p_in_end ) {
266 p_line_start = p_in;
267 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
268 while( p_in < p_line_end )
270 /* are we in the left part of the line */
271 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
273 if ( b_left_to_right )
274 *p_out = *p_in;
275 else
276 *p_out = *( p_line_end - ( p_in - p_line_start ) );
278 else
280 if ( b_left_to_right )
281 *p_out = *( p_line_start + ( p_line_end - p_in ) );
282 else
283 *p_out = *p_in;
285 p_in++;
286 p_out++;
288 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
289 p_out += p_outpic->p[i_plane].i_pitch
290 - p_outpic->p[i_plane].i_visible_pitch;
294 /*****************************************************************************
295 * YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
296 *****************************************************************************
297 * This function mirrors image vertically. It iterates for all lines in
298 * image and for every line, iterates for 4-byte chucks, properly mirroring
299 * them vertically (swapping Y components and keeping Cb and Cr components).
300 * This function works only for YUV422 packed formats.
301 *****************************************************************************/
302 static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
303 int i_plane, bool b_left_to_right,
304 bool b_y_is_odd )
306 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
308 p_in = p_pic->p[i_plane].p_pixels;
309 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
310 * p_pic->p[i_plane].i_pitch;
311 p_out = p_outpic->p[i_plane].p_pixels;
313 while( p_in < p_in_end )
315 p_line_start = p_in;
316 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
317 while( p_in < p_line_end )
319 /* are we in the left part of the line */
320 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
322 if ( b_left_to_right )
324 *p_out++ = *p_in++;
325 *p_out++ = *p_in++;
326 *p_out++ = *p_in++;
327 *p_out++ = *p_in++;
329 else
331 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
332 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
333 p_in += 4;
334 p_out += 4;
337 else
339 if ( b_left_to_right )
341 uint8_t *p_start = p_line_end - ( p_in - p_line_start );
342 YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
343 p_in += 4;
344 p_out += 4;
346 else
348 *p_out++ = *p_in++;
349 *p_out++ = *p_in++;
350 *p_out++ = *p_in++;
351 *p_out++ = *p_in++;
355 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
356 p_out += p_outpic->p[i_plane].i_pitch
357 - p_outpic->p[i_plane].i_visible_pitch;
361 /*****************************************************************************
362 * YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
363 *****************************************************************************
364 * This function mirrors two consecutive pixels of 4 byte size. Depending of
365 * position of Y components (b_y_is_odd is true if Y components are first and
366 * third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
367 * component positions are preserved.
368 *****************************************************************************/
369 static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
370 bool b_y_is_odd )
372 if ( b_y_is_odd )
374 /* swap Y components */
375 *p_dst = *( p_src + 2 );
376 *( p_dst + 2 ) = *p_src;
377 /* copy Cb and Cr components */
378 *( p_dst + 1 ) = *( p_src + 1 );
379 *( p_dst + 3 ) = *( p_src + 3 );
381 else{
382 /* swap Y components */
383 *( p_dst + 1 )= *( p_src + 3 );
384 *( p_dst + 3 ) = *( p_src + 1);
385 /* copy Cb and Cr components */
386 *p_dst = *( p_src + 2 );
387 *( p_dst + 2 ) = *p_src;
391 /*****************************************************************************
392 * RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
393 *****************************************************************************
394 * This function mirrors image vertically. It iterates for all lines in
395 * image and for every line, it iterates for 3-byte chunks.
396 * This function works only for RV24 formats.
397 *****************************************************************************/
398 static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
399 int i_plane, bool b_left_to_right )
401 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
403 p_in = p_pic->p[i_plane].p_pixels;
404 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
405 * p_pic->p[i_plane].i_pitch;
406 p_out = p_outpic->p[i_plane].p_pixels;
408 while( p_in < p_in_end )
410 p_line_start = p_in;
411 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
412 while( p_in < p_line_end )
414 /* are we in the left part of the line */
415 if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
417 if ( b_left_to_right )
419 *p_out++ = *p_in++;
420 *p_out++ = *p_in++;
421 *p_out++ = *p_in++;
423 else
425 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
426 p_in += 3;
427 *p_out++ = *p_pixel++;
428 *p_out++ = *p_pixel++;
429 *p_out++ = *p_pixel++;
432 else
434 if ( b_left_to_right )
436 uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
437 p_in += 3;
438 *p_out++ = *p_pixel++;
439 *p_out++ = *p_pixel++;
440 *p_out++ = *p_pixel++;
442 else
444 *p_out++ = *p_in++;
445 *p_out++ = *p_in++;
446 *p_out++ = *p_in++;
450 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
451 p_out += p_outpic->p[i_plane].i_pitch
452 - p_outpic->p[i_plane].i_visible_pitch;
456 /*****************************************************************************
457 * RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
458 *****************************************************************************
459 * This function mirrors image vertically. It iterates for all lines in
460 * image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
461 * This function works only for RV32 formats.
462 *****************************************************************************/
463 static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
464 int i_plane, bool b_left_to_right )
466 uint8_t *p_in, *p_in_end, *p_out;
468 p_in = p_pic->p[i_plane].p_pixels;
469 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
470 * p_pic->p[i_plane].i_pitch;
471 p_out = p_outpic->p[i_plane].p_pixels;
473 while( p_in < p_in_end )
475 uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
476 p_in32 = (uint32_t*) p_in;
477 p_out32 = (uint32_t*) p_out;
478 p_line_start32 = p_in32;
479 p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
481 while( p_in32 < p_line_end32 )
483 /* are we in the left part of the line */
484 if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
486 if ( b_left_to_right )
488 *p_out32++ = *p_in32++;
490 else
492 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
493 p_in32++;
494 *p_out++ = *p_pixel32;
497 else
499 if ( b_left_to_right )
501 uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
502 p_in32++;
503 *p_out++ = *p_pixel32;
505 else
507 *p_out32++ = *p_in32++;
511 p_in = (uint8_t*) p_in32;
512 p_out = (uint8_t*) p_out32;
513 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
514 p_out += p_outpic->p[i_plane].i_pitch
515 - p_outpic->p[i_plane].i_visible_pitch;
519 /*****************************************************************************
520 * HorizontalMirror: Mirrors horizontally image byte by byte
521 *****************************************************************************
522 * This function mirrors image horizontally. It iterates for all lines in
523 * image and for every line, determines if it should be copied, and if it does,
524 * finds opposite line in picture and copies current byte from opposite line.
525 * This function works both for planar, packed and RV24 formats.
526 *****************************************************************************/
527 static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
528 bool b_top_to_bottom )
530 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
532 int i_curr_line = 0;
533 int i_max_lines = p_pic->p[i_plane].i_visible_lines;
535 p_in = p_pic->p[i_plane].p_pixels;
536 p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
537 * p_pic->p[i_plane].i_pitch;
538 p_out = p_outpic->p[i_plane].p_pixels;
540 while( p_in < p_in_end )
542 p_line_start = p_in;
543 p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
544 while( p_in < p_line_end )
546 uint8_t *p_inverse_line;
547 /* are we in the upper part of the picture */
548 if ( i_curr_line < i_max_lines/2 )
550 if ( b_top_to_bottom )
552 *p_out = *p_in;
554 else
556 /* determines line inverse to current line */
557 p_inverse_line = p_pic->p[i_plane].p_pixels +
558 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
559 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
562 else
564 if ( b_top_to_bottom )
566 /* determines line inverse to current line */
567 p_inverse_line = p_pic->p[i_plane].p_pixels +
568 ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
569 *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
571 else
573 *p_out = *p_in;
576 p_in++;
577 p_out++;
579 i_curr_line++;
580 p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
581 p_out += p_outpic->p[i_plane].i_pitch
582 - p_outpic->p[i_plane].i_visible_pitch;
586 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
587 vlc_value_t oldval, vlc_value_t newval, void *p_data )
589 (void) p_this; (void)oldval;
590 filter_sys_t *p_sys = p_data;
592 if( !strcmp( psz_var, CFG_PREFIX "split" ) )
593 atomic_store( &p_sys->i_split, newval.i_int );
594 else /* CFG_PREFIX "direction" */
595 atomic_store( &p_sys->i_direction, newval.i_int );
597 return VLC_SUCCESS;