]> git.sesse.net Git - vlc/blob - modules/video_filter/transform.c
input options whitelisting, step 2 (refs #1371)
[vlc] / modules / video_filter / transform.c
1 /*****************************************************************************
2  * transform.c : transform image module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
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.
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 General Public License for more details.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30
31 #include "filter_common.h"
32 #include "filter_picture.h"
33
34 #define TRANSFORM_MODE_HFLIP   1
35 #define TRANSFORM_MODE_VFLIP   2
36 #define TRANSFORM_MODE_90      3
37 #define TRANSFORM_MODE_180     4
38 #define TRANSFORM_MODE_270     5
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int  Create    ( vlc_object_t * );
44 static void Destroy   ( vlc_object_t * );
45
46 static int  Init      ( vout_thread_t * );
47 static void End       ( vout_thread_t * );
48 static void Render    ( vout_thread_t *, picture_t * );
49
50 static void FilterPlanar( vout_thread_t *, const picture_t *, picture_t * );
51 static void FilterYUYV( vout_thread_t *, const picture_t *, picture_t * );
52
53 static int  SendEvents( vlc_object_t *, char const *,
54                         vlc_value_t, vlc_value_t, void * );
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 #define TYPE_TEXT N_("Transform type")
60 #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
61
62 static const char *type_list[] = { "90", "180", "270", "hflip", "vflip" };
63 static const char *type_list_text[] = { N_("Rotate by 90 degrees"),
64   N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
65   N_("Flip horizontally"), N_("Flip vertically") };
66
67 #define CFG_PREFIX "transform-"
68
69 vlc_module_begin();
70     set_description( _("Video transformation filter") );
71     set_shortname( _("Transformation"));
72     set_capability( "video filter", 0 );
73     set_category( CAT_VIDEO );
74     set_subcategory( SUBCAT_VIDEO_VFILTER );
75
76     add_string( CFG_PREFIX "type", "90", NULL,
77                           TYPE_TEXT, TYPE_LONGTEXT, VLC_FALSE);
78         change_safe();
79         change_string_list( type_list, type_list_text, 0);
80
81     add_shortcut( "transform" );
82     set_callbacks( Create, Destroy );
83 vlc_module_end();
84
85 static const char *ppsz_filter_options[] = {
86     "type", NULL
87 };
88
89 /*****************************************************************************
90  * vout_sys_t: Transform video output method descriptor
91  *****************************************************************************
92  * This structure is part of the video output thread descriptor.
93  * It describes the Transform specific properties of an output thread.
94  *****************************************************************************/
95 struct vout_sys_t
96 {
97     int i_mode;
98     vlc_bool_t b_rotation;
99     vout_thread_t *p_vout;
100
101     void (*pf_filter)( vout_thread_t *, const picture_t *, picture_t * );
102 };
103
104 /*****************************************************************************
105  * Control: control facility for the vout (forwards to child vout)
106  *****************************************************************************/
107 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
108 {
109     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
110 }
111
112 /*****************************************************************************
113  * Create: allocates Transform video thread output method
114  *****************************************************************************
115  * This function allocates and initializes a Transform vout method.
116  *****************************************************************************/
117 static int Create( vlc_object_t *p_this )
118 {
119     vout_thread_t *p_vout = (vout_thread_t *)p_this;
120     char *psz_method;
121
122     /* Allocate structure */
123     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
124     if( p_vout->p_sys == NULL )
125     {
126         msg_Err( p_vout, "out of memory" );
127         return VLC_ENOMEM;
128     }
129
130     p_vout->pf_init = Init;
131     p_vout->pf_end = End;
132     p_vout->pf_manage = NULL;
133     p_vout->pf_render = Render;
134     p_vout->pf_display = NULL;
135     p_vout->pf_control = Control;
136
137     config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
138                            p_vout->p_cfg );
139
140     /* Look what method was requested */
141     psz_method = var_CreateGetNonEmptyString( p_vout, "transform-type" );
142
143     switch( p_vout->fmt_in.i_chroma )
144     {
145         CASE_PLANAR_YUV
146         case VLC_FOURCC('G','R','E','Y'):
147             p_vout->p_sys->pf_filter = FilterPlanar;
148             break;
149
150         CASE_PACKED_YUV_422
151             p_vout->p_sys->pf_filter = FilterYUYV;
152             break;
153
154         default:
155             msg_Err( p_vout, "Unsupported chroma" );
156             free( p_vout->p_sys );
157             return VLC_EGENERIC;
158     }
159
160     if( psz_method == NULL )
161     {
162         msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
163         msg_Err( p_vout, "no valid transform mode provided, using '90'" );
164         p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
165         p_vout->p_sys->b_rotation = 1;
166     }
167     else
168     {
169         if( !strcmp( psz_method, "hflip" ) )
170         {
171             p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
172             p_vout->p_sys->b_rotation = 0;
173         }
174         else if( !strcmp( psz_method, "vflip" ) )
175         {
176             p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
177             p_vout->p_sys->b_rotation = 0;
178         }
179         else if( !strcmp( psz_method, "90" ) )
180         {
181             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
182             p_vout->p_sys->b_rotation = 1;
183         }
184         else if( !strcmp( psz_method, "180" ) )
185         {
186             p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
187             p_vout->p_sys->b_rotation = 0;
188         }
189         else if( !strcmp( psz_method, "270" ) )
190         {
191             p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
192             p_vout->p_sys->b_rotation = 1;
193         }
194         else
195         {
196             msg_Err( p_vout, "no valid transform mode provided, using '90'" );
197             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
198             p_vout->p_sys->b_rotation = 1;
199         }
200
201         free( psz_method );
202     }
203
204     return VLC_SUCCESS;
205 }
206
207 /*****************************************************************************
208  * Init: initialize Transform video thread output method
209  *****************************************************************************/
210 static int Init( vout_thread_t *p_vout )
211 {
212     int i_index;
213     picture_t *p_pic;
214     video_format_t fmt;
215
216     I_OUTPUTPICTURES = 0;
217     memset( &fmt, 0, sizeof(video_format_t) );
218
219     /* Initialize the output structure */
220     p_vout->output.i_chroma = p_vout->render.i_chroma;
221     p_vout->output.i_width  = p_vout->render.i_width;
222     p_vout->output.i_height = p_vout->render.i_height;
223     p_vout->output.i_aspect = p_vout->render.i_aspect;
224     p_vout->fmt_out = p_vout->fmt_in;
225     fmt = p_vout->fmt_out;
226
227     /* Try to open the real video output */
228     msg_Dbg( p_vout, "spawning the real video output" );
229
230     if( p_vout->p_sys->b_rotation )
231     {
232         fmt.i_width = p_vout->fmt_out.i_height;
233         fmt.i_visible_width = p_vout->fmt_out.i_visible_height;
234         fmt.i_x_offset = p_vout->fmt_out.i_y_offset;
235
236         fmt.i_height = p_vout->fmt_out.i_width;
237         fmt.i_visible_height = p_vout->fmt_out.i_visible_width;
238         fmt.i_y_offset = p_vout->fmt_out.i_x_offset;
239
240         fmt.i_aspect = VOUT_ASPECT_FACTOR *
241             (uint64_t)VOUT_ASPECT_FACTOR / fmt.i_aspect;
242
243         fmt.i_sar_num = p_vout->fmt_out.i_sar_den;
244         fmt.i_sar_den = p_vout->fmt_out.i_sar_num;
245     }
246
247     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
248
249     /* Everything failed */
250     if( p_vout->p_sys->p_vout == NULL )
251     {
252         msg_Err( p_vout, "cannot open vout, aborting" );
253         return VLC_EGENERIC;
254     }
255
256     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
257
258     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
259
260     ADD_PARENT_CALLBACKS( SendEventsToChild );
261
262     return VLC_SUCCESS;
263 }
264
265 /*****************************************************************************
266  * End: terminate Transform video thread output method
267  *****************************************************************************/
268 static void End( vout_thread_t *p_vout )
269 {
270     int i_index;
271
272     /* Free the fake output buffers we allocated */
273     for( i_index = I_OUTPUTPICTURES ; i_index ; )
274     {
275         i_index--;
276         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
277     }
278 }
279
280 /*****************************************************************************
281  * Destroy: destroy Transform video thread output method
282  *****************************************************************************
283  * Terminate an output method created by TransformCreateOutputMethod
284  *****************************************************************************/
285 static void Destroy( vlc_object_t *p_this )
286 {
287     vout_thread_t *p_vout = (vout_thread_t *)p_this;
288
289     if( p_vout->p_sys->p_vout )
290     {
291         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
292         vlc_object_detach( p_vout->p_sys->p_vout );
293         vout_Destroy( p_vout->p_sys->p_vout );
294     }
295
296     DEL_PARENT_CALLBACKS( SendEventsToChild );
297
298     free( p_vout->p_sys );
299 }
300
301 /*****************************************************************************
302  * Render: displays previously rendered output
303  *****************************************************************************
304  * This function send the currently rendered image to Transform image, waits
305  * until it is displayed and switch the two rendering buffers, preparing next
306  * frame.
307  *****************************************************************************/
308 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
309 {
310     picture_t *p_outpic;
311
312     /* This is a new frame. Get a structure from the video_output. */
313     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
314               == NULL )
315     {
316         if( p_vout->b_die || p_vout->b_error )
317         {
318             return;
319         }
320         msleep( VOUT_OUTMEM_SLEEP );
321     }
322
323     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
324     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
325
326     p_vout->p_sys->pf_filter( p_vout, p_pic, p_outpic );
327
328     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
329
330     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
331 }
332
333 /*****************************************************************************
334  * SendEvents: forward mouse and keyboard events to the parent p_vout
335  *****************************************************************************/
336 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
337                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
338 {
339     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
340     vlc_value_t sentval = newval;
341
342     /* Translate the mouse coordinates */
343     if( !strcmp( psz_var, "mouse-x" ) )
344     {
345         switch( p_vout->p_sys->i_mode )
346         {
347         case TRANSFORM_MODE_270:
348             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
349                              - sentval.i_int;
350         case TRANSFORM_MODE_90:
351             var_Set( p_vout, "mouse-y", sentval );
352             return VLC_SUCCESS;
353
354         case TRANSFORM_MODE_180:
355         case TRANSFORM_MODE_HFLIP:
356             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
357                              - sentval.i_int;
358             break;
359
360         case TRANSFORM_MODE_VFLIP:
361         default:
362             break;
363         }
364     }
365     else if( !strcmp( psz_var, "mouse-y" ) )
366     {
367         switch( p_vout->p_sys->i_mode )
368         {
369         case TRANSFORM_MODE_90:
370             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
371                              - sentval.i_int;
372         case TRANSFORM_MODE_270:
373             var_Set( p_vout, "mouse-x", sentval );
374             return VLC_SUCCESS;
375
376         case TRANSFORM_MODE_180:
377         case TRANSFORM_MODE_VFLIP:
378             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
379                              - sentval.i_int;
380             break;
381
382         case TRANSFORM_MODE_HFLIP:
383         default:
384             break;
385         }
386     }
387
388     var_Set( p_vout, psz_var, sentval );
389
390     return VLC_SUCCESS;
391 }
392
393 /*****************************************************************************
394  * SendEventsToChild: forward events to the child/children vout
395  *****************************************************************************/
396 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
397                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
398 {
399     vout_thread_t *p_vout = (vout_thread_t *)p_this;
400     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
401     return VLC_SUCCESS;
402 }
403
404 static void FilterPlanar( vout_thread_t *p_vout,
405                           const picture_t *p_pic, picture_t *p_outpic )
406 {
407     int i_index;
408     switch( p_vout->p_sys->i_mode )
409     {
410         case TRANSFORM_MODE_90:
411             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
412             {
413                 int i_pitch = p_pic->p[i_index].i_pitch;
414
415                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
416
417                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
418                 uint8_t *p_out_end = p_out +
419                     p_outpic->p[i_index].i_visible_lines *
420                     p_outpic->p[i_index].i_pitch;
421
422                 for( ; p_out < p_out_end ; )
423                 {
424                     uint8_t *p_line_end;
425
426                     p_out_end -= p_outpic->p[i_index].i_pitch
427                                   - p_outpic->p[i_index].i_visible_pitch;
428                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
429                         i_pitch;
430
431                     for( ; p_in < p_line_end ; )
432                     {
433                         p_line_end -= i_pitch;
434                         *(--p_out_end) = *p_line_end;
435                     }
436
437                     p_in++;
438                 }
439             }
440             break;
441
442         case TRANSFORM_MODE_180:
443             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
444             {
445                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
446                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
447                                             * p_pic->p[i_index].i_pitch;
448
449                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
450
451                 for( ; p_in < p_in_end ; )
452                 {
453                     uint8_t *p_line_start = p_in_end
454                                              - p_pic->p[i_index].i_pitch;
455                     p_in_end -= p_pic->p[i_index].i_pitch
456                                  - p_pic->p[i_index].i_visible_pitch;
457
458                     for( ; p_line_start < p_in_end ; )
459                     {
460                         *p_out++ = *(--p_in_end);
461                     }
462
463                     p_out += p_outpic->p[i_index].i_pitch
464                               - p_outpic->p[i_index].i_visible_pitch;
465                 }
466             }
467             break;
468
469         case TRANSFORM_MODE_270:
470             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
471             {
472                 int i_pitch = p_pic->p[i_index].i_pitch;
473
474                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
475
476                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
477                 uint8_t *p_out_end = p_out +
478                     p_outpic->p[i_index].i_visible_lines *
479                     p_outpic->p[i_index].i_pitch;
480
481                 for( ; p_out < p_out_end ; )
482                 {
483                     uint8_t *p_in_end;
484
485                     p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
486                         i_pitch;
487
488                     for( ; p_in < p_in_end ; )
489                     {
490                         p_in_end -= i_pitch;
491                         *p_out++ = *p_in_end;
492                     }
493
494                     p_out += p_outpic->p[i_index].i_pitch
495                               - p_outpic->p[i_index].i_visible_pitch;
496                     p_in++;
497                 }
498             }
499             break;
500
501         case TRANSFORM_MODE_HFLIP:
502             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
503             {
504                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
505                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
506                                             * p_pic->p[i_index].i_pitch;
507
508                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
509
510                 for( ; p_in < p_in_end ; )
511                 {
512                     p_in_end -= p_pic->p[i_index].i_pitch;
513                     p_vout->p_libvlc->pf_memcpy( p_out, p_in_end,
514                                            p_pic->p[i_index].i_visible_pitch );
515                     p_out += p_pic->p[i_index].i_pitch;
516                 }
517             }
518             break;
519
520         case TRANSFORM_MODE_VFLIP:
521             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
522             {
523                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
524                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
525                                          * p_pic->p[i_index].i_pitch;
526
527                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
528
529                 for( ; p_in < p_in_end ; )
530                 {
531                     uint8_t *p_line_end = p_in
532                                         + p_pic->p[i_index].i_visible_pitch;
533
534                     for( ; p_in < p_line_end ; )
535                     {
536                         *p_out++ = *(--p_line_end);
537                     }
538
539                     p_in += p_pic->p[i_index].i_pitch;
540                 }
541             }
542             break;
543
544         default:
545             break;
546     }
547 }
548
549 static void FilterYUYV( vout_thread_t *p_vout,
550                         const picture_t *p_pic, picture_t *p_outpic )
551 {
552     int i_index;
553     int i_y_offset, i_u_offset, i_v_offset;
554     if( GetPackedYuvOffsets( p_pic->format.i_chroma, &i_y_offset,
555                              &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
556         return;
557
558     switch( p_vout->p_sys->i_mode )
559     {
560         case TRANSFORM_MODE_90:
561             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
562             {
563                 int i_pitch = p_pic->p[i_index].i_pitch;
564
565                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
566
567                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
568                 uint8_t *p_out_end = p_out +
569                     p_outpic->p[i_index].i_visible_lines *
570                     p_outpic->p[i_index].i_pitch;
571
572                 int i_offset  = i_u_offset;
573                 int i_offset2 = i_v_offset;
574                 for( ; p_out < p_out_end ; )
575                 {
576                     uint8_t *p_line_end;
577
578                     p_out_end -= p_outpic->p[i_index].i_pitch
579                                   - p_outpic->p[i_index].i_visible_pitch;
580                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
581                         i_pitch;
582
583                     for( ; p_in < p_line_end ; )
584                     {
585                         p_line_end -= i_pitch;
586                         p_out_end -= 4;
587                         p_out_end[i_y_offset+2] = p_line_end[i_y_offset];
588                         p_out_end[i_u_offset] = p_line_end[i_offset];
589                         p_line_end -= i_pitch;
590                         p_out_end[i_y_offset] = p_line_end[i_y_offset];
591                         p_out_end[i_v_offset] = p_line_end[i_offset2];
592                     }
593
594                     p_in += 2;
595
596                     {
597                         int a = i_offset;
598                         i_offset = i_offset2;
599                         i_offset2 = a;
600                     }
601                 }
602             }
603             break;
604
605         case TRANSFORM_MODE_180:
606             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
607             {
608                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
609                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
610                                             * p_pic->p[i_index].i_pitch;
611
612                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
613
614                 for( ; p_in < p_in_end ; )
615                 {
616                     uint8_t *p_line_start = p_in_end
617                                              - p_pic->p[i_index].i_pitch;
618                     p_in_end -= p_pic->p[i_index].i_pitch
619                                  - p_pic->p[i_index].i_visible_pitch;
620
621                     for( ; p_line_start < p_in_end ; )
622                     {
623                         p_in_end -= 4;
624                         p_out[i_y_offset] = p_in_end[i_y_offset+2];
625                         p_out[i_u_offset] = p_in_end[i_u_offset];
626                         p_out[i_y_offset+2] = p_in_end[i_y_offset];
627                         p_out[i_v_offset] = p_in_end[i_v_offset];
628                         p_out += 4;
629                     }
630
631                     p_out += p_outpic->p[i_index].i_pitch
632                               - p_outpic->p[i_index].i_visible_pitch;
633                 }
634             }
635             break;
636
637         case TRANSFORM_MODE_270:
638             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
639             {
640                 int i_pitch = p_pic->p[i_index].i_pitch;
641
642                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
643
644                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
645                 uint8_t *p_out_end = p_out +
646                     p_outpic->p[i_index].i_visible_lines *
647                     p_outpic->p[i_index].i_pitch;
648
649                 int i_offset  = i_u_offset;
650                 int i_offset2 = i_v_offset;
651                 for( ; p_out < p_out_end ; )
652                 {
653                     uint8_t *p_in_end;
654
655                     p_in_end = p_in
656                              + p_pic->p[i_index].i_visible_lines * i_pitch;
657
658                     for( ; p_in < p_in_end ; )
659                     {
660                         p_in_end -= i_pitch;
661                         p_out[i_y_offset] = p_in_end[i_y_offset];
662                         p_out[i_u_offset] = p_in_end[i_offset];
663                         p_in_end -= i_pitch;
664                         p_out[i_y_offset+2] = p_in_end[i_y_offset];
665                         p_out[i_v_offset] = p_in_end[i_offset2];
666                         p_out += 4;
667                     }
668
669                     p_out += p_outpic->p[i_index].i_pitch
670                            - p_outpic->p[i_index].i_visible_pitch;
671                     p_in += 2;
672
673                     {
674                         int a = i_offset;
675                         i_offset = i_offset2;
676                         i_offset2 = a;
677                     }
678                 }
679             }
680             break;
681
682         case TRANSFORM_MODE_HFLIP:
683             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
684             {
685                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
686                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
687                                             * p_pic->p[i_index].i_pitch;
688
689                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
690
691                 for( ; p_in < p_in_end ; )
692                 {
693                     p_in_end -= p_pic->p[i_index].i_pitch;
694                     p_vout->p_libvlc->pf_memcpy( p_out, p_in_end,
695                                            p_pic->p[i_index].i_visible_pitch );
696                     p_out += p_pic->p[i_index].i_pitch;
697                 }
698             }
699             break;
700
701         case TRANSFORM_MODE_VFLIP:
702             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
703             {
704                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
705                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
706                                          * p_pic->p[i_index].i_pitch;
707
708                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
709
710                 for( ; p_in < p_in_end ; )
711                 {
712                     uint8_t *p_line_end = p_in
713                                         + p_pic->p[i_index].i_visible_pitch;
714
715                     for( ; p_in < p_line_end ; )
716                     {
717                         p_line_end -= 4;
718                         p_out[i_y_offset] = p_line_end[i_y_offset+2];
719                         p_out[i_u_offset] = p_line_end[i_u_offset];
720                         p_out[i_y_offset+2] = p_line_end[i_y_offset];
721                         p_out[i_v_offset] = p_line_end[i_v_offset];
722                         p_out += 4;
723                     }
724
725                     p_in += p_pic->p[i_index].i_pitch;
726                 }
727             }
728             break;
729
730         default:
731             break;
732     }
733 }