]> git.sesse.net Git - vlc/blob - plugins/chroma/i420_yuy2.c
6447750acdc6d76e766013cbbe22bb992ce9b24b
[vlc] / plugins / 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.10 2002/07/23 00:39:16 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_chroma_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 void chroma_getfunctions ( function_list_t * p_function_list );
48
49 static int  chroma_Init         ( vout_thread_t *p_vout );
50 static void chroma_End          ( vout_thread_t *p_vout );
51
52 static void I420_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
53 static void I420_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
54 static void I420_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
55 static void I420_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
56 static void I420_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
57 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
58 static void I420_Y211           ( vout_thread_t *, picture_t *, picture_t * );
59 #endif
60
61 #ifdef MODULE_NAME_IS_chroma_i420_yuy2_mmx
62 static unsigned long long i_00ffw;
63 static unsigned long long i_80w;
64 #endif
65
66 /*****************************************************************************
67  * Build configuration tree.
68  *****************************************************************************/
69 MODULE_CONFIG_START
70 MODULE_CONFIG_STOP
71
72 MODULE_INIT_START
73 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
74     SET_DESCRIPTION( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) )
75     ADD_CAPABILITY( CHROMA, 80 )
76 #elif defined (MODULE_NAME_IS_chroma_i420_yuy2_mmx)
77     SET_DESCRIPTION( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) )
78     ADD_CAPABILITY( CHROMA, 100 )
79     ADD_REQUIREMENT( MMX )
80     /* Initialize MMX-specific constants */
81     i_00ffw = 0x00ff00ff00ff00ff;
82     i_80w   = 0x0000000080808080;
83 #endif
84 MODULE_INIT_STOP
85
86 MODULE_ACTIVATE_START
87     chroma_getfunctions( &p_module->p_functions->chroma );
88 MODULE_ACTIVATE_STOP
89
90 MODULE_DEACTIVATE_START
91 MODULE_DEACTIVATE_STOP
92
93 /*****************************************************************************
94  * Functions exported as capabilities. They are declared as static so that
95  * we don't pollute the namespace too much.
96  *****************************************************************************/
97 static void chroma_getfunctions( function_list_t * p_function_list )
98 {
99     p_function_list->functions.chroma.pf_init = chroma_Init;
100     p_function_list->functions.chroma.pf_end  = chroma_End;
101 }
102
103 /*****************************************************************************
104  * chroma_Init: allocate a chroma function
105  *****************************************************************************
106  * This function allocates and initializes a chroma function
107  *****************************************************************************/
108 static int chroma_Init( vout_thread_t *p_vout )
109 {
110     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
111     {
112         return -1;
113     }
114
115     switch( p_vout->render.i_chroma )
116     {
117         case VLC_FOURCC('Y','V','1','2'):
118         case VLC_FOURCC('I','4','2','0'):
119         case VLC_FOURCC('I','Y','U','V'):
120             switch( p_vout->output.i_chroma )
121             {
122                 case VLC_FOURCC('Y','U','Y','2'):
123                 case VLC_FOURCC('Y','U','N','V'):
124                     p_vout->chroma.pf_convert = I420_YUY2;
125                     break;
126
127                 case VLC_FOURCC('Y','V','Y','U'):
128                     p_vout->chroma.pf_convert = I420_YVYU;
129                     break;
130
131                 case VLC_FOURCC('U','Y','V','Y'):
132                 case VLC_FOURCC('U','Y','N','V'):
133                 case VLC_FOURCC('Y','4','2','2'):
134                     p_vout->chroma.pf_convert = I420_UYVY;
135                     break;
136
137                 case VLC_FOURCC('I','U','Y','V'):
138                     p_vout->chroma.pf_convert = I420_IUYV;
139                     break;
140
141                 case VLC_FOURCC('c','y','u','v'):
142                     p_vout->chroma.pf_convert = I420_cyuv;
143                     break;
144
145 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
146                 case VLC_FOURCC('Y','2','1','1'):
147                     p_vout->chroma.pf_convert = I420_Y211;
148                     break;
149 #endif
150
151                 default:
152                     return -1;
153             }
154             break;
155
156         default:
157             return -1;
158     }
159
160     return 0;
161 }
162
163 /*****************************************************************************
164  * chroma_End: free the chroma function
165  *****************************************************************************
166  * This function frees the previously allocated chroma function
167  *****************************************************************************/
168 static void chroma_End( vout_thread_t *p_vout )
169 {
170     ;
171 }
172
173 /* Following functions are local */
174
175 /*****************************************************************************
176  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
177  *****************************************************************************/
178 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
179                                               picture_t *p_dest )
180 {
181     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
182     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
183     u8 *p_u = p_source->U_PIXELS;
184     u8 *p_v = p_source->V_PIXELS;
185
186     int i_x, i_y;
187
188     const int i_source_margin = p_source->p->i_pitch
189                                  - p_source->p->i_visible_pitch;
190     const int i_dest_margin = p_dest->p->i_pitch
191                                - p_dest->p->i_visible_pitch;
192
193     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
194     {
195         p_line1 = p_line2;
196         p_line2 += p_dest->p->i_pitch;
197
198         p_y1 = p_y2;
199         p_y2 += p_source->p[Y_PLANE].i_pitch;
200
201         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
202         {
203 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
204             C_YUV420_YUYV( );
205             C_YUV420_YUYV( );
206             C_YUV420_YUYV( );
207             C_YUV420_YUYV( );
208 #else
209             MMX_CALL( MMX_YUV420_YUYV );
210 #endif
211         }
212
213         p_y1 += i_source_margin;
214         p_y2 += i_source_margin;
215         p_line1 += i_dest_margin;
216         p_line2 += i_dest_margin;
217     }
218 }
219
220 /*****************************************************************************
221  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
222  *****************************************************************************/
223 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
224                                               picture_t *p_dest )
225 {
226     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
227     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
228     u8 *p_u = p_source->U_PIXELS;
229     u8 *p_v = p_source->V_PIXELS;
230
231     int i_x, i_y;
232
233     const int i_source_margin = p_source->p->i_pitch
234                                  - p_source->p->i_visible_pitch;
235     const int i_dest_margin = p_dest->p->i_pitch
236                                - p_dest->p->i_visible_pitch;
237
238     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
239     {
240         p_line1 = p_line2;
241         p_line2 += p_dest->p->i_pitch;
242
243         p_y1 = p_y2;
244         p_y2 += p_source->p[Y_PLANE].i_pitch;
245
246         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
247         {
248 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
249             C_YUV420_YVYU( );
250             C_YUV420_YVYU( );
251             C_YUV420_YVYU( );
252             C_YUV420_YVYU( );
253 #else
254             MMX_CALL( MMX_YUV420_YVYU );
255 #endif
256         }
257
258         p_y1 += i_source_margin;
259         p_y2 += i_source_margin;
260         p_line1 += i_dest_margin;
261         p_line2 += i_dest_margin;
262     }
263 }
264
265 /*****************************************************************************
266  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
267  *****************************************************************************/
268 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
269                                               picture_t *p_dest )
270 {
271     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
272     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
273     u8 *p_u = p_source->U_PIXELS;
274     u8 *p_v = p_source->V_PIXELS;
275
276     int i_x, i_y;
277
278     const int i_source_margin = p_source->p->i_pitch
279                                  - p_source->p->i_visible_pitch;
280     const int i_dest_margin = p_dest->p->i_pitch
281                                - p_dest->p->i_visible_pitch;
282
283     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
284     {
285         p_line1 = p_line2;
286         p_line2 += p_dest->p->i_pitch;
287
288         p_y1 = p_y2;
289         p_y2 += p_source->p[Y_PLANE].i_pitch;
290
291         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
292         {
293 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
294             C_YUV420_UYVY( );
295             C_YUV420_UYVY( );
296             C_YUV420_UYVY( );
297             C_YUV420_UYVY( );
298 #else
299             MMX_CALL( MMX_YUV420_UYVY );
300 #endif
301         }
302
303         p_y1 += i_source_margin;
304         p_y2 += i_source_margin;
305         p_line1 += i_dest_margin;
306         p_line2 += i_dest_margin;
307     }
308 }
309
310 /*****************************************************************************
311  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
312  *****************************************************************************/
313 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
314                                               picture_t *p_dest )
315 {
316     /* FIXME: TODO ! */
317     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
318 }
319
320 /*****************************************************************************
321  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
322  *****************************************************************************/
323 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
324                                               picture_t *p_dest )
325 {
326     u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch
327                                       + p_dest->p->i_pitch;
328     u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch;
329     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
330     u8 *p_u = p_source->U_PIXELS;
331     u8 *p_v = p_source->V_PIXELS;
332
333     int i_x, i_y;
334
335     const int i_source_margin = p_source->p->i_pitch
336                                  - p_source->p->i_visible_pitch;
337     const int i_dest_margin = p_dest->p->i_pitch
338                                - p_dest->p->i_visible_pitch;
339
340     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
341     {
342         p_line1 -= 3 * p_dest->p->i_pitch;
343         p_line2 -= 3 * p_dest->p->i_pitch;
344
345         p_y1 = p_y2;
346         p_y2 += p_source->p[Y_PLANE].i_pitch;
347
348         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
349         {
350 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
351             C_YUV420_UYVY( );
352             C_YUV420_UYVY( );
353             C_YUV420_UYVY( );
354             C_YUV420_UYVY( );
355 #else
356             MMX_CALL( MMX_YUV420_UYVY );
357 #endif
358         }
359
360         p_y1 += i_source_margin;
361         p_y2 += i_source_margin;
362         p_line1 += i_dest_margin;
363         p_line2 += i_dest_margin;
364     }
365 }
366
367 /*****************************************************************************
368  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
369  *****************************************************************************/
370 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
371 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
372                                               picture_t *p_dest )
373 {
374     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
375     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
376     u8 *p_u = p_source->U_PIXELS;
377     u8 *p_v = p_source->V_PIXELS;
378
379     int i_x, i_y;
380
381     const int i_source_margin = p_source->p->i_pitch
382                                  - p_source->p->i_visible_pitch;
383     const int i_dest_margin = p_dest->p->i_pitch
384                                - p_dest->p->i_visible_pitch;
385
386     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
387     {
388         p_line1 = p_line2;
389         p_line2 += p_dest->p->i_pitch;
390
391         p_y1 = p_y2;
392         p_y2 += p_source->p[Y_PLANE].i_pitch;
393
394         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
395         {
396             C_YUV420_Y211( );
397             C_YUV420_Y211( );
398         }
399
400         p_y1 += i_source_margin;
401         p_y2 += i_source_margin;
402         p_line1 += i_dest_margin;
403         p_line2 += i_dest_margin;
404     }
405 }
406 #endif
407