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