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