string review by Christophe Mutricy aka xtophe
[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.5 2004/01/25 17:20:18 kuehne 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 uint64_t i_00ffw;
59 static uint64_t 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 = 0x00ff00ff00ff00ffULL;
75     i_80w   = 0x0000000080808080ULL;
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     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
151     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
152     uint8_t *p_u = p_source->U_PIXELS;
153     uint8_t *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     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
196     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
197     uint8_t *p_u = p_source->U_PIXELS;
198     uint8_t *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     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
241     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
242     uint8_t *p_u = p_source->U_PIXELS;
243     uint8_t *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     uint8_t *p_line1 = p_dest->p->p_pixels +
296                        p_dest->p->i_lines * p_dest->p->i_pitch
297                        + p_dest->p->i_pitch;
298     uint8_t *p_line2 = p_dest->p->p_pixels +
299                        p_dest->p->i_lines * p_dest->p->i_pitch;
300     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
301     uint8_t *p_u = p_source->U_PIXELS;
302     uint8_t *p_v = p_source->V_PIXELS;
303
304     int i_x, i_y;
305
306     const int i_source_margin = p_source->p->i_pitch
307                                  - p_source->p->i_visible_pitch;
308     const int i_dest_margin = p_dest->p->i_pitch
309                                - p_dest->p->i_visible_pitch;
310
311     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
312     {
313         p_line1 -= 3 * p_dest->p->i_pitch;
314         p_line2 -= 3 * p_dest->p->i_pitch;
315
316         p_y1 = p_y2;
317         p_y2 += p_source->p[Y_PLANE].i_pitch;
318
319         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
320         {
321 #if defined (MODULE_NAME_IS_i420_yuy2)
322             C_YUV420_UYVY( );
323             C_YUV420_UYVY( );
324             C_YUV420_UYVY( );
325             C_YUV420_UYVY( );
326 #else
327             MMX_CALL( MMX_YUV420_UYVY );
328 #endif
329         }
330
331         p_y1 += i_source_margin;
332         p_y2 += i_source_margin;
333         p_line1 += i_dest_margin;
334         p_line2 += i_dest_margin;
335     }
336 }
337
338 /*****************************************************************************
339  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
340  *****************************************************************************/
341 #if defined (MODULE_NAME_IS_i420_yuy2)
342 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
343                                               picture_t *p_dest )
344 {
345     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
346     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
347     uint8_t *p_u = p_source->U_PIXELS;
348     uint8_t *p_v = p_source->V_PIXELS;
349
350     int i_x, i_y;
351
352     const int i_source_margin = p_source->p->i_pitch
353                                  - p_source->p->i_visible_pitch;
354     const int i_dest_margin = p_dest->p->i_pitch
355                                - p_dest->p->i_visible_pitch;
356
357     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
358     {
359         p_line1 = p_line2;
360         p_line2 += p_dest->p->i_pitch;
361
362         p_y1 = p_y2;
363         p_y2 += p_source->p[Y_PLANE].i_pitch;
364
365         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
366         {
367             C_YUV420_Y211( );
368             C_YUV420_Y211( );
369         }
370
371         p_y1 += i_source_margin;
372         p_y2 += i_source_margin;
373         p_line1 += i_dest_margin;
374         p_line2 += i_dest_margin;
375     }
376 }
377 #endif
378