upnp: remove m_server_list_lock, p_server_list is already protected by s_lock
[vlc.git] / modules / video_filter / mirror.c
1 /*****************************************************************************
2  * mirror.c : Mirror video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_atomic.h>
37 #include <vlc_filter.h>
38 #include "filter_picture.h"
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int  Create      ( vlc_object_t * );
44 static void Destroy     ( vlc_object_t * );
45
46 static picture_t *Filter( filter_t *, picture_t * );
47 static void VerticalMirror( picture_t *, picture_t *, int plane, bool );
48 static void HorizontalMirror( picture_t *, picture_t *, int, bool );
49 static void PlanarVerticalMirror( picture_t *, picture_t *, int plane, bool );
50 static void YUV422VerticalMirror( picture_t *, picture_t *, int plane, bool, bool );
51 static void RV24VerticalMirror( picture_t *, picture_t *, int plane, bool );
52 static void RV32VerticalMirror( picture_t *, picture_t *, int plane, bool );
53
54 static void YUV422Mirror2Pixels( uint8_t *, uint8_t *, bool );
55
56 static const char *const ppsz_filter_options[] = {
57     "split", "direction", NULL
58 };
59
60 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63 #define ORIENTATION_TEXT N_("Mirror orientation")
64 #define ORIENTATION_LONGTEXT N_("Defines orientation of the mirror splitting. \
65     Can be vertical or horizontal" )
66 static const int pi_orientation_values[] = { 0, 1 };
67 static const char *const ppsz_orientation_descriptions[] = {
68   N_("Vertical"), N_("Horizontal") };
69
70 #define DIRECTION_TEXT N_("Direction")
71 #define DIRECTION_LONGTEXT N_("Direction of the mirroring" )
72 static const int pi_direction_values[] = { 0, 1 };
73 static const char *const ppsz_direction_descriptions[] = {
74   N_("Left to right/Top to bottom"), N_("Right to left/Bottom to top") };
75
76 #define CFG_PREFIX "mirror-"
77
78 vlc_module_begin ()
79     set_description( N_("Mirror video filter") )
80     set_shortname( N_("Mirror video" ))
81     set_help( N_("Splits video in two same parts, like in a mirror") )
82     set_category( CAT_VIDEO )
83     set_subcategory( SUBCAT_VIDEO_VFILTER )
84     set_capability( "video filter2", 0 )
85     add_integer( CFG_PREFIX "split", 0, ORIENTATION_TEXT,
86                 ORIENTATION_LONGTEXT, false )
87         change_integer_list( pi_orientation_values,
88                             ppsz_orientation_descriptions )
89     add_integer( CFG_PREFIX "direction", 0, DIRECTION_TEXT,
90                 DIRECTION_LONGTEXT, false )
91         change_integer_list( pi_direction_values, ppsz_direction_descriptions )
92     set_callbacks( Create, Destroy )
93 vlc_module_end ()
94
95 /*****************************************************************************
96  * callback prototypes
97  *****************************************************************************/
98 static int FilterCallback( vlc_object_t *, char const *,
99                            vlc_value_t, vlc_value_t, void * );
100
101 /*****************************************************************************
102  * filter_sys_t: adjust filter method descriptor
103  *****************************************************************************/
104 struct filter_sys_t
105 {
106     atomic_int i_split;
107     atomic_int i_direction;
108 };
109
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 )
116 {
117     filter_t *p_filter = (filter_t *)p_this;
118     filter_sys_t *p_sys;
119
120     switch( p_filter->fmt_in.video.i_chroma )
121     {
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;
129
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;
134     }
135
136     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
137     {
138         msg_Err( p_filter, "Input and output chromas don't match" );
139         return VLC_EGENERIC;
140     }
141
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;
146
147     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
148                        p_filter->p_cfg );
149     atomic_init( &p_sys->i_split,
150                  var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" ) );
151     atomic_init( &p_sys->i_direction,
152                  var_CreateGetIntegerCommand( p_filter,
153                                                     CFG_PREFIX "direction" ) );
154
155     var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
156     var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
157
158     p_filter->pf_video_filter = Filter;
159
160     return VLC_SUCCESS;
161 }
162
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 )
169 {
170     filter_t *p_filter = (filter_t *)p_this;
171     filter_sys_t *p_sys = p_filter->p_sys;
172
173     var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
174     var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
175     free( p_sys );
176 }
177
178 /*****************************************************************************
179  * Render: displays previously rendered output
180  *****************************************************************************
181  * This function send the currently rendered image to Mirror image, waits
182  * until it is displayed and switch the two rendering buffers, preparing next
183  * frame.
184  *****************************************************************************/
185 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
186 {
187     picture_t *p_outpic;
188     bool b_vertical_split, b_left_to_right;
189
190     if( !p_pic ) return NULL;
191
192     filter_sys_t *p_sys = p_filter->p_sys;
193     b_vertical_split = !atomic_load( &p_sys->i_split );
194     b_left_to_right = !atomic_load( &p_sys->i_direction );
195
196     p_outpic = filter_NewPicture( p_filter );
197     if( !p_outpic )
198     {
199         msg_Warn( p_filter, "can't get output picture" );
200         picture_Release( p_pic );
201         return NULL;
202     }
203
204     for( int i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
205     {
206         if ( b_vertical_split )
207             VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
208         else
209             HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
210     }
211
212     return CopyInfoAndRelease( p_outpic, p_pic );
213 }
214
215 /*****************************************************************************
216  * VerticalMirror: Mirrors vertically image
217  *****************************************************************************
218  * This function is a simple delegate to concrete function for vertical
219  * mirroring depending on the input format.
220  *****************************************************************************/
221 static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
222                            bool b_left_to_right )
223 {
224     switch( p_pic->format.i_chroma )
225     {
226         CASE_PLANAR_YUV_SQUARE
227             PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
228             break;
229         case VLC_CODEC_YUYV:
230         case VLC_CODEC_YVYU:
231             YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
232                                  true );
233             break;
234         case VLC_CODEC_UYVY:
235             break;
236         case VLC_CODEC_RGB24:
237             RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
238             break;
239         case VLC_CODEC_RGB32:
240             RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
241             break;
242         default:
243             vlc_assert_unreachable();
244     }
245 }
246
247 /*****************************************************************************
248  * PlanarVerticalMirror: Mirrors vertically image byte by byte
249  *****************************************************************************
250  * This function mirrors image vertically. It iterates for all lines in
251  * image and for every line, it mirrors byte for byte if needed.
252  * This function works for planar formats only.
253  *****************************************************************************/
254 static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
255                                  int i_plane, bool b_left_to_right )
256 {
257     uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
258
259     p_in = p_pic->p[i_plane].p_pixels;
260     p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
261         * p_pic->p[i_plane].i_pitch;
262     p_out = p_outpic->p[i_plane].p_pixels;
263
264     while( p_in < p_in_end ) {
265         p_line_start = p_in;
266         p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
267         while( p_in < p_line_end )
268         {
269             /* are we in the left part of the line */
270             if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
271             {
272                 if ( b_left_to_right )
273                     *p_out = *p_in;
274                 else
275                     *p_out = *( p_line_end - ( p_in - p_line_start ) );
276             }
277             else
278             {
279                 if ( b_left_to_right )
280                     *p_out = *( p_line_start + ( p_line_end - p_in ) );
281                 else
282                     *p_out = *p_in;
283             }
284             p_in++;
285             p_out++;
286         }
287         p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
288         p_out += p_outpic->p[i_plane].i_pitch
289             - p_outpic->p[i_plane].i_visible_pitch;
290     }
291 }
292
293 /*****************************************************************************
294  * YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
295  *****************************************************************************
296  * This function mirrors image vertically. It iterates for all lines in
297  * image and for every line, iterates for 4-byte chucks, properly mirroring
298  * them vertically (swapping Y components and keeping Cb and Cr components).
299  * This function works only for YUV422 packed formats.
300  *****************************************************************************/
301 static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
302                                  int i_plane, bool b_left_to_right,
303                                  bool b_y_is_odd )
304 {
305     uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
306
307     p_in = p_pic->p[i_plane].p_pixels;
308     p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
309         * p_pic->p[i_plane].i_pitch;
310     p_out = p_outpic->p[i_plane].p_pixels;
311
312     while( p_in < p_in_end )
313     {
314         p_line_start = p_in;
315         p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
316         while( p_in < p_line_end )
317         {
318             /* are we in the left part of the line */
319             if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
320             {
321                 if ( b_left_to_right )
322                 {
323                     *p_out++ = *p_in++;
324                     *p_out++ = *p_in++;
325                     *p_out++ = *p_in++;
326                     *p_out++ = *p_in++;
327                 }
328                 else
329                 {
330                     uint8_t *p_start = p_line_end - ( p_in - p_line_start );
331                     YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
332                     p_in += 4;
333                     p_out += 4;
334                 }
335             }
336             else
337             {
338                 if ( b_left_to_right )
339                 {
340                     uint8_t *p_start = p_line_end - ( p_in - p_line_start );
341                     YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
342                     p_in += 4;
343                     p_out += 4;
344                 }
345                 else
346                 {
347                     *p_out++ = *p_in++;
348                     *p_out++ = *p_in++;
349                     *p_out++ = *p_in++;
350                     *p_out++ = *p_in++;
351                 }
352             }
353         }
354         p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
355         p_out += p_outpic->p[i_plane].i_pitch
356             - p_outpic->p[i_plane].i_visible_pitch;
357     }
358 }
359
360 /*****************************************************************************
361  * YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
362  *****************************************************************************
363  * This function mirrors two consecutive pixels of 4 byte size. Depending of
364  * position of Y components (b_y_is_odd is true if Y components are first and
365  * third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
366  * component positions are preserved.
367  *****************************************************************************/
368 static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
369                                 bool b_y_is_odd )
370 {
371     if ( b_y_is_odd )
372     {
373         /* swap Y components */
374         *p_dst = *( p_src + 2 );
375         *( p_dst + 2 ) = *p_src;
376         /* copy Cb and Cr components */
377         *( p_dst + 1 ) = *( p_src + 1 );
378         *( p_dst + 3 ) = *( p_src + 3 );
379     }
380     else{
381         /* swap Y components */
382         *( p_dst + 1 )= *( p_src + 3 );
383         *( p_dst + 3 ) = *( p_src + 1);
384         /* copy Cb and Cr components */
385         *p_dst = *( p_src + 2 );
386         *( p_dst + 2 ) = *p_src;
387     }
388 }
389
390 /*****************************************************************************
391  * RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
392  *****************************************************************************
393  * This function mirrors image vertically. It iterates for all lines in
394  * image and for every line, it iterates for 3-byte chunks.
395  * This function works only for RV24 formats.
396  *****************************************************************************/
397 static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
398                                  int i_plane, bool b_left_to_right )
399 {
400     uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
401
402     p_in = p_pic->p[i_plane].p_pixels;
403     p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
404         * p_pic->p[i_plane].i_pitch;
405     p_out = p_outpic->p[i_plane].p_pixels;
406
407     while( p_in < p_in_end )
408     {
409         p_line_start = p_in;
410         p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
411         while( p_in < p_line_end )
412         {
413             /* are we in the left part of the line */
414             if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
415             {
416                 if ( b_left_to_right )
417                 {
418                     *p_out++ = *p_in++;
419                     *p_out++ = *p_in++;
420                     *p_out++ = *p_in++;
421                 }
422                 else
423                 {
424                     uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
425                     p_in += 3;
426                     *p_out++ = *p_pixel++;
427                     *p_out++ = *p_pixel++;
428                     *p_out++ = *p_pixel++;
429                 }
430             }
431             else
432             {
433                 if ( b_left_to_right )
434                 {
435                     uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
436                     p_in += 3;
437                     *p_out++ = *p_pixel++;
438                     *p_out++ = *p_pixel++;
439                     *p_out++ = *p_pixel++;
440                 }
441                 else
442                 {
443                     *p_out++ = *p_in++;
444                     *p_out++ = *p_in++;
445                     *p_out++ = *p_in++;
446                 }
447             }
448         }
449         p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
450         p_out += p_outpic->p[i_plane].i_pitch
451             - p_outpic->p[i_plane].i_visible_pitch;
452     }
453 }
454
455 /*****************************************************************************
456  * RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
457  *****************************************************************************
458  * This function mirrors image vertically. It iterates for all lines in
459  * image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
460  * This function works only for RV32 formats.
461  *****************************************************************************/
462 static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
463                                  int i_plane, bool b_left_to_right )
464 {
465     uint8_t *p_in, *p_in_end, *p_out;
466
467     p_in = p_pic->p[i_plane].p_pixels;
468     p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
469         * p_pic->p[i_plane].i_pitch;
470     p_out = p_outpic->p[i_plane].p_pixels;
471
472     while( p_in < p_in_end )
473     {
474         uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
475         p_in32 = (uint32_t*) p_in;
476         p_out32 = (uint32_t*) p_out;
477         p_line_start32 = p_in32;
478         p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
479
480         while( p_in32 < p_line_end32 )
481         {
482             /* are we in the left part of the line */
483             if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
484             {
485                 if ( b_left_to_right )
486                 {
487                     *p_out32++ = *p_in32++;
488                 }
489                 else
490                 {
491                     uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
492                     p_in32++;
493                     *p_out++ = *p_pixel32;
494                 }
495             }
496             else
497             {
498                 if ( b_left_to_right )
499                 {
500                     uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
501                     p_in32++;
502                     *p_out++ = *p_pixel32;
503                 }
504                 else
505                 {
506                     *p_out32++ = *p_in32++;
507                 }
508             }
509         }
510         p_in = (uint8_t*) p_in32;
511         p_out = (uint8_t*) p_out32;
512         p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
513         p_out += p_outpic->p[i_plane].i_pitch
514             - p_outpic->p[i_plane].i_visible_pitch;
515     }
516 }
517
518 /*****************************************************************************
519  * HorizontalMirror: Mirrors horizontally image byte by byte
520  *****************************************************************************
521  * This function mirrors image horizontally. It iterates for all lines in
522  * image and for every line, determines if it should be copied, and if it does,
523  * finds opposite line in picture and copies current byte from opposite line.
524  * This function works both for planar, packed and RV24 formats.
525  *****************************************************************************/
526 static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
527                              bool b_top_to_bottom )
528 {
529     uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
530
531     int i_curr_line = 0;
532     int i_max_lines = p_pic->p[i_plane].i_visible_lines;
533
534     p_in = p_pic->p[i_plane].p_pixels;
535     p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
536         * p_pic->p[i_plane].i_pitch;
537     p_out = p_outpic->p[i_plane].p_pixels;
538
539     while( p_in < p_in_end )
540     {
541         p_line_start = p_in;
542         p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
543         while( p_in < p_line_end )
544         {
545             uint8_t *p_inverse_line;
546             /* are we in the upper part of the picture */
547             if ( i_curr_line < i_max_lines/2 )
548             {
549                 if ( b_top_to_bottom )
550                 {
551                     *p_out = *p_in;
552                 }
553                 else
554                 {
555                     /* determines line inverse to current line */
556                     p_inverse_line = p_pic->p[i_plane].p_pixels +
557                         ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
558                     *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
559                 }
560             }
561             else
562             {
563                 if ( b_top_to_bottom )
564                 {
565                     /* determines line inverse to current line */
566                     p_inverse_line = p_pic->p[i_plane].p_pixels +
567                         ( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
568                     *p_out = *( p_inverse_line + ( p_in - p_line_start ) );
569                 }
570                 else
571                 {
572                     *p_out = *p_in;
573                 }
574             }
575             p_in++;
576             p_out++;
577         }
578         i_curr_line++;
579         p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
580         p_out += p_outpic->p[i_plane].i_pitch
581             - p_outpic->p[i_plane].i_visible_pitch;
582     }
583 }
584
585 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
586                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
587 {
588     (void) p_this; (void)oldval;
589     filter_sys_t *p_sys = p_data;
590
591     if( !strcmp( psz_var, CFG_PREFIX "split" ) )
592         atomic_store( &p_sys->i_split, newval.i_int );
593     else /* CFG_PREFIX "direction" */
594         atomic_store( &p_sys->i_direction, newval.i_int );
595
596     return VLC_SUCCESS;
597 }