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