* ./debian/rules: moved the gtk_main and gnome_main plugins to the gvlc
[vlc.git] / modules / video_chroma / i420_yuy2.c
1 /*****************************************************************************
2  * i420_yuy2.c : YUV to YUV conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: i420_yuy2.c,v 1.1 2002/08/04 17:23:43 sam Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <string.h>                                            /* strerror() */
29 #include <stdlib.h>                                      /* malloc(), free() */
30
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33
34 #include "i420_yuy2.h"
35
36 #define SRC_FOURCC  "I420,IYUV,YV12"
37
38 #if defined (MODULE_NAME_IS_i420_yuy2)
39 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
40 #else
41 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
42 #endif
43
44 /*****************************************************************************
45  * Local and extern prototypes.
46  *****************************************************************************/
47 static int  Activate ( vlc_object_t * );
48
49 static void I420_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
50 static void I420_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
51 static void I420_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
52 static void I420_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
53 static void I420_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
54 #if defined (MODULE_NAME_IS_i420_yuy2)
55 static void I420_Y211           ( vout_thread_t *, picture_t *, picture_t * );
56 #endif
57
58 #ifdef MODULE_NAME_IS_i420_yuy2_mmx
59 static unsigned long long i_00ffw;
60 static unsigned long long i_80w;
61 #endif
62
63 /*****************************************************************************
64  * Module descriptor.
65  *****************************************************************************/
66 vlc_module_begin();
67 #if defined (MODULE_NAME_IS_i420_yuy2)
68     set_description( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) );
69     set_capability( "chroma", 80 );
70 #elif defined (MODULE_NAME_IS_i420_yuy2_mmx)
71     set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
72     set_capability( "chroma", 100 );
73     add_requirement( MMX );
74     /* Initialize MMX-specific constants */
75     i_00ffw = 0x00ff00ff00ff00ff;
76     i_80w   = 0x0000000080808080;
77 #endif
78     set_callbacks( Activate, NULL );
79 vlc_module_end();
80
81 /*****************************************************************************
82  * Activate: allocate a chroma function
83  *****************************************************************************
84  * This function allocates and initializes a chroma function
85  *****************************************************************************/
86 static int Activate( vlc_object_t *p_this )
87 {
88     vout_thread_t *p_vout = (vout_thread_t *)p_this;
89
90     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
91     {
92         return -1;
93     }
94
95     switch( p_vout->render.i_chroma )
96     {
97         case VLC_FOURCC('Y','V','1','2'):
98         case VLC_FOURCC('I','4','2','0'):
99         case VLC_FOURCC('I','Y','U','V'):
100             switch( p_vout->output.i_chroma )
101             {
102                 case VLC_FOURCC('Y','U','Y','2'):
103                 case VLC_FOURCC('Y','U','N','V'):
104                     p_vout->chroma.pf_convert = I420_YUY2;
105                     break;
106
107                 case VLC_FOURCC('Y','V','Y','U'):
108                     p_vout->chroma.pf_convert = I420_YVYU;
109                     break;
110
111                 case VLC_FOURCC('U','Y','V','Y'):
112                 case VLC_FOURCC('U','Y','N','V'):
113                 case VLC_FOURCC('Y','4','2','2'):
114                     p_vout->chroma.pf_convert = I420_UYVY;
115                     break;
116
117                 case VLC_FOURCC('I','U','Y','V'):
118                     p_vout->chroma.pf_convert = I420_IUYV;
119                     break;
120
121                 case VLC_FOURCC('c','y','u','v'):
122                     p_vout->chroma.pf_convert = I420_cyuv;
123                     break;
124
125 #if defined (MODULE_NAME_IS_i420_yuy2)
126                 case VLC_FOURCC('Y','2','1','1'):
127                     p_vout->chroma.pf_convert = I420_Y211;
128                     break;
129 #endif
130
131                 default:
132                     return -1;
133             }
134             break;
135
136         default:
137             return -1;
138     }
139
140     return 0;
141 }
142
143 /* Following functions are local */
144
145 /*****************************************************************************
146  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
147  *****************************************************************************/
148 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
149                                               picture_t *p_dest )
150 {
151     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
152     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
153     u8 *p_u = p_source->U_PIXELS;
154     u8 *p_v = p_source->V_PIXELS;
155
156     int i_x, i_y;
157
158     const int i_source_margin = p_source->p->i_pitch
159                                  - p_source->p->i_visible_pitch;
160     const int i_dest_margin = p_dest->p->i_pitch
161                                - p_dest->p->i_visible_pitch;
162
163     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
164     {
165         p_line1 = p_line2;
166         p_line2 += p_dest->p->i_pitch;
167
168         p_y1 = p_y2;
169         p_y2 += p_source->p[Y_PLANE].i_pitch;
170
171         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
172         {
173 #if defined (MODULE_NAME_IS_i420_yuy2)
174             C_YUV420_YUYV( );
175             C_YUV420_YUYV( );
176             C_YUV420_YUYV( );
177             C_YUV420_YUYV( );
178 #else
179             MMX_CALL( MMX_YUV420_YUYV );
180 #endif
181         }
182
183         p_y1 += i_source_margin;
184         p_y2 += i_source_margin;
185         p_line1 += i_dest_margin;
186         p_line2 += i_dest_margin;
187     }
188 }
189
190 /*****************************************************************************
191  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
192  *****************************************************************************/
193 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
194                                               picture_t *p_dest )
195 {
196     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
197     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
198     u8 *p_u = p_source->U_PIXELS;
199     u8 *p_v = p_source->V_PIXELS;
200
201     int i_x, i_y;
202
203     const int i_source_margin = p_source->p->i_pitch
204                                  - p_source->p->i_visible_pitch;
205     const int i_dest_margin = p_dest->p->i_pitch
206                                - p_dest->p->i_visible_pitch;
207
208     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
209     {
210         p_line1 = p_line2;
211         p_line2 += p_dest->p->i_pitch;
212
213         p_y1 = p_y2;
214         p_y2 += p_source->p[Y_PLANE].i_pitch;
215
216         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
217         {
218 #if defined (MODULE_NAME_IS_i420_yuy2)
219             C_YUV420_YVYU( );
220             C_YUV420_YVYU( );
221             C_YUV420_YVYU( );
222             C_YUV420_YVYU( );
223 #else
224             MMX_CALL( MMX_YUV420_YVYU );
225 #endif
226         }
227
228         p_y1 += i_source_margin;
229         p_y2 += i_source_margin;
230         p_line1 += i_dest_margin;
231         p_line2 += i_dest_margin;
232     }
233 }
234
235 /*****************************************************************************
236  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
237  *****************************************************************************/
238 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
239                                               picture_t *p_dest )
240 {
241     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
242     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
243     u8 *p_u = p_source->U_PIXELS;
244     u8 *p_v = p_source->V_PIXELS;
245
246     int i_x, i_y;
247
248     const int i_source_margin = p_source->p->i_pitch
249                                  - p_source->p->i_visible_pitch;
250     const int i_dest_margin = p_dest->p->i_pitch
251                                - p_dest->p->i_visible_pitch;
252
253     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
254     {
255         p_line1 = p_line2;
256         p_line2 += p_dest->p->i_pitch;
257
258         p_y1 = p_y2;
259         p_y2 += p_source->p[Y_PLANE].i_pitch;
260
261         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
262         {
263 #if defined (MODULE_NAME_IS_i420_yuy2)
264             C_YUV420_UYVY( );
265             C_YUV420_UYVY( );
266             C_YUV420_UYVY( );
267             C_YUV420_UYVY( );
268 #else
269             MMX_CALL( MMX_YUV420_UYVY );
270 #endif
271         }
272
273         p_y1 += i_source_margin;
274         p_y2 += i_source_margin;
275         p_line1 += i_dest_margin;
276         p_line2 += i_dest_margin;
277     }
278 }
279
280 /*****************************************************************************
281  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
282  *****************************************************************************/
283 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
284                                               picture_t *p_dest )
285 {
286     /* FIXME: TODO ! */
287     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
288 }
289
290 /*****************************************************************************
291  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
292  *****************************************************************************/
293 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
294                                               picture_t *p_dest )
295 {
296     u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch
297                                       + p_dest->p->i_pitch;
298     u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch;
299     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
300     u8 *p_u = p_source->U_PIXELS;
301     u8 *p_v = p_source->V_PIXELS;
302
303     int i_x, i_y;
304
305     const int i_source_margin = p_source->p->i_pitch
306                                  - p_source->p->i_visible_pitch;
307     const int i_dest_margin = p_dest->p->i_pitch
308                                - p_dest->p->i_visible_pitch;
309
310     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
311     {
312         p_line1 -= 3 * p_dest->p->i_pitch;
313         p_line2 -= 3 * p_dest->p->i_pitch;
314
315         p_y1 = p_y2;
316         p_y2 += p_source->p[Y_PLANE].i_pitch;
317
318         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
319         {
320 #if defined (MODULE_NAME_IS_i420_yuy2)
321             C_YUV420_UYVY( );
322             C_YUV420_UYVY( );
323             C_YUV420_UYVY( );
324             C_YUV420_UYVY( );
325 #else
326             MMX_CALL( MMX_YUV420_UYVY );
327 #endif
328         }
329
330         p_y1 += i_source_margin;
331         p_y2 += i_source_margin;
332         p_line1 += i_dest_margin;
333         p_line2 += i_dest_margin;
334     }
335 }
336
337 /*****************************************************************************
338  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
339  *****************************************************************************/
340 #if defined (MODULE_NAME_IS_i420_yuy2)
341 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
342                                               picture_t *p_dest )
343 {
344     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
345     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
346     u8 *p_u = p_source->U_PIXELS;
347     u8 *p_v = p_source->V_PIXELS;
348
349     int i_x, i_y;
350
351     const int i_source_margin = p_source->p->i_pitch
352                                  - p_source->p->i_visible_pitch;
353     const int i_dest_margin = p_dest->p->i_pitch
354                                - p_dest->p->i_visible_pitch;
355
356     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
357     {
358         p_line1 = p_line2;
359         p_line2 += p_dest->p->i_pitch;
360
361         p_y1 = p_y2;
362         p_y2 += p_source->p[Y_PLANE].i_pitch;
363
364         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
365         {
366             C_YUV420_Y211( );
367             C_YUV420_Y211( );
368         }
369
370         p_y1 += i_source_margin;
371         p_y2 += i_source_margin;
372         p_line1 += i_dest_margin;
373         p_line2 += i_dest_margin;
374     }
375 }
376 #endif
377