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