]> git.sesse.net Git - vlc/blob - plugins/chroma/i420_yuy2.c
* ./BUGS: added a list of known bugs. Please add your findings!
[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.1 2002/01/04 14:01:34 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 <math.h>                                            /* exp(), pow() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdlib.h>                                      /* malloc(), free() */
31
32 #include <videolan/vlc.h>
33
34 #include "video.h"
35 #include "video_output.h"
36
37 #include "i420_yuy2.h"
38
39 #define SRC_FOURCC  "I420/IYUV/YV12"
40
41 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
42 #    define DEST_FOURCC "YUY2/YUNV/YVYU/UYVY/UYNV/Y422/IUYV/cyuv/Y211"
43 #else
44 #    define DEST_FOURCC "YUY2/YUNV/YVYU/UYVY/UYNV/Y422/IUYV/cyuv"
45 #endif
46
47 /*****************************************************************************
48  * Local and extern prototypes.
49  *****************************************************************************/
50 static void chroma_getfunctions ( function_list_t * p_function_list );
51
52 static int  chroma_Probe        ( probedata_t *p_data );
53 static int  chroma_Init         ( vout_thread_t *p_vout );
54 static void chroma_End          ( vout_thread_t *p_vout );
55
56 static void I420_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
57 static void I420_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
58 static void I420_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
59 static void I420_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
60 static void I420_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
61 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
62 static void I420_Y211           ( vout_thread_t *, picture_t *, picture_t * );
63 #endif
64
65 /*****************************************************************************
66  * Build configuration tree.
67  *****************************************************************************/
68 MODULE_CONFIG_START
69 MODULE_CONFIG_STOP
70
71 MODULE_INIT_START
72 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
73     SET_DESCRIPTION( "conversions from " SRC_FOURCC " to " DEST_FOURCC )
74     ADD_CAPABILITY( CHROMA, 80 )
75 #elif defined (MODULE_NAME_IS_chroma_i420_yuy2_mmx)
76     SET_DESCRIPTION( "MMX conversions from " SRC_FOURCC " to " DEST_FOURCC )
77     ADD_CAPABILITY( CHROMA, 100 )
78     ADD_REQUIREMENT( MMX )
79 #endif
80 MODULE_INIT_STOP
81
82 MODULE_ACTIVATE_START
83     chroma_getfunctions( &p_module->p_functions->chroma );
84 MODULE_ACTIVATE_STOP
85
86 MODULE_DEACTIVATE_START
87 MODULE_DEACTIVATE_STOP
88
89 /*****************************************************************************
90  * Functions exported as capabilities. They are declared as static so that
91  * we don't pollute the namespace too much.
92  *****************************************************************************/
93 static void chroma_getfunctions( function_list_t * p_function_list )
94 {
95     p_function_list->pf_probe = chroma_Probe;
96     p_function_list->functions.chroma.pf_init = chroma_Init;
97     p_function_list->functions.chroma.pf_end  = chroma_End;
98 }
99
100 /*****************************************************************************
101  * chroma_Probe: return a score
102  *****************************************************************************
103  * This function checks that we can handle the required data
104  *****************************************************************************/
105 static int chroma_Probe( probedata_t *p_data )
106 {
107     if( p_data->chroma.p_render->i_width & 1
108          || p_data->chroma.p_render->i_height & 1 )
109     {
110         return 0;
111     }
112
113     switch( p_data->chroma.p_render->i_chroma )
114     {
115         case FOURCC_YV12:
116         case FOURCC_I420:
117         case FOURCC_IYUV:
118             switch( p_data->chroma.p_output->i_chroma )
119             {
120                 case FOURCC_YUY2:
121                 case FOURCC_YUNV:
122                     break;
123
124                 case FOURCC_YVYU:
125                     break;
126
127                 case FOURCC_UYVY:
128                 case FOURCC_UYNV:
129                 case FOURCC_Y422:
130                     break;
131
132                 case FOURCC_IUYV:
133                     break;
134
135                 case FOURCC_cyuv:
136                     break;
137
138 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
139                 case FOURCC_Y211:
140                     break;
141 #endif
142
143                 default:
144                     return 0;
145             }
146             break;
147
148         default:
149             return 0;
150     }
151
152     return 100;
153 }
154
155 /*****************************************************************************
156  * chroma_Init: allocate a chroma function
157  *****************************************************************************
158  * This function allocates and initializes a chroma function
159  *****************************************************************************/
160 static int chroma_Init( vout_thread_t *p_vout )
161 {
162     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
163     {
164         return -1;
165     }
166
167     switch( p_vout->render.i_chroma )
168     {
169         case FOURCC_YV12:
170         case FOURCC_I420:
171         case FOURCC_IYUV:
172             switch( p_vout->output.i_chroma )
173             {
174                 case FOURCC_YUY2:
175                 case FOURCC_YUNV:
176                     p_vout->chroma.pf_convert = I420_YUY2;
177                     break;
178
179                 case FOURCC_YVYU:
180                     p_vout->chroma.pf_convert = I420_YVYU;
181                     break;
182
183                 case FOURCC_UYVY:
184                 case FOURCC_UYNV:
185                 case FOURCC_Y422:
186                     p_vout->chroma.pf_convert = I420_UYVY;
187                     break;
188
189                 case FOURCC_IUYV:
190                     p_vout->chroma.pf_convert = I420_IUYV;
191                     break;
192
193                 case FOURCC_cyuv:
194                     p_vout->chroma.pf_convert = I420_cyuv;
195                     break;
196
197 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
198                 case FOURCC_Y211:
199                     p_vout->chroma.pf_convert = I420_Y211;
200                     break;
201 #endif
202
203                 default:
204                     return -1;
205             }
206             break;
207
208         default:
209             return -1;
210     }
211     
212     return 0; 
213 }
214
215 /*****************************************************************************
216  * chroma_End: free the chroma function
217  *****************************************************************************
218  * This function frees the previously allocated chroma function
219  *****************************************************************************/
220 static void chroma_End( vout_thread_t *p_vout )
221 {
222     ;
223 }
224
225 /* Following functions are local */
226
227 /*****************************************************************************
228  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
229  *****************************************************************************/
230 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
231                                               picture_t *p_dest )
232 {
233     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
234     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
235     u8 *p_u = p_source->U_PIXELS;
236     u8 *p_v = p_source->V_PIXELS;
237
238     int i_x, i_y;
239
240     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
241     {
242         p_line1 = p_line2;
243         p_line2 += p_dest->p->i_pitch;
244
245         p_y1 = p_y2;
246         p_y2 += p_source->p[Y_PLANE].i_pitch;
247
248         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
249         {
250 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
251             C_YUV420_YUYV( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
252             C_YUV420_YUYV( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
253             C_YUV420_YUYV( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
254             C_YUV420_YUYV( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
255 #else
256             __asm__( ".align 8" MMX_YUV420_YUYV
257                      : : "r" (p_line1), "r" (p_line2),
258                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
259
260             p_line1 += 8; p_line2 += 8;
261             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
262
263             __asm__( ".align 8" MMX_YUV420_YUYV
264                      : : "r" (p_line1), "r" (p_line2),
265                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
266
267             p_line1 += 8; p_line2 += 8;
268             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
269 #endif
270         }
271     }
272 }
273
274 /*****************************************************************************
275  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
276  *****************************************************************************/
277 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
278                                               picture_t *p_dest )
279 {
280     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
281     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
282     u8 *p_u = p_source->U_PIXELS;
283     u8 *p_v = p_source->V_PIXELS;
284
285     int i_x, i_y;
286
287     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
288     {
289         p_line1 = p_line2;
290         p_line2 += p_dest->p->i_pitch;
291
292         p_y1 = p_y2;
293         p_y2 += p_source->p[Y_PLANE].i_pitch;
294
295         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
296         {
297 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
298             C_YUV420_YVYU( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
299             C_YUV420_YVYU( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
300             C_YUV420_YVYU( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
301             C_YUV420_YVYU( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
302 #else
303             __asm__( ".align 8" MMX_YUV420_YVYU
304                      : : "r" (p_line1), "r" (p_line2),
305                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
306
307             p_line1 += 8; p_line2 += 8;
308             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
309
310             __asm__( ".align 8" MMX_YUV420_YVYU
311                      : : "r" (p_line1), "r" (p_line2),
312                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
313
314             p_line1 += 8; p_line2 += 8;
315             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
316 #endif
317         }
318     }
319 }
320
321 /*****************************************************************************
322  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
323  *****************************************************************************/
324 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
325                                               picture_t *p_dest )
326 {
327     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
328     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
329     u8 *p_u = p_source->U_PIXELS;
330     u8 *p_v = p_source->V_PIXELS;
331
332     int i_x, i_y;
333
334     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
335     {
336         p_line1 = p_line2;
337         p_line2 += p_dest->p->i_pitch;
338
339         p_y1 = p_y2;
340         p_y2 += p_source->p[Y_PLANE].i_pitch;
341
342         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
343         {
344 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
345             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
346             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
347             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
348             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
349 #else
350             __asm__( ".align 8" MMX_YUV420_UYVY
351                      : : "r" (p_line1), "r" (p_line2),
352                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
353
354             p_line1 += 8; p_line2 += 8;
355             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
356
357             __asm__( ".align 8" MMX_YUV420_UYVY
358                      : : "r" (p_line1), "r" (p_line2),
359                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
360
361             p_line1 += 8; p_line2 += 8;
362             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
363 #endif
364         }
365     }
366 }
367
368 /*****************************************************************************
369  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
370  *****************************************************************************/
371 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
372                                               picture_t *p_dest )
373 {
374     /* FIXME: TODO ! */
375     intf_ErrMsg( "chroma error: I420_IUYV unimplemented, "
376                  "please harass <sam@zoy.org>" );
377 }
378
379 /*****************************************************************************
380  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
381  *****************************************************************************/
382 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
383                                               picture_t *p_dest )
384 {
385     u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch
386                                       + p_dest->p->i_pitch;
387     u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch;
388     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
389     u8 *p_u = p_source->U_PIXELS;
390     u8 *p_v = p_source->V_PIXELS;
391
392     int i_x, i_y;
393
394     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
395     {
396         p_line1 -= 3 * p_dest->p->i_pitch;
397         p_line2 -= 3 * p_dest->p->i_pitch;
398
399         p_y1 = p_y2;
400         p_y2 += p_source->p[Y_PLANE].i_pitch;
401
402         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
403         {
404 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
405             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
406             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
407             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
408             C_YUV420_UYVY( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
409 #else
410             __asm__( ".align 8" MMX_YUV420_UYVY
411                      : : "r" (p_line1), "r" (p_line2),
412                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
413
414             p_line1 += 8; p_line2 += 8;
415             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
416
417             __asm__( ".align 8" MMX_YUV420_UYVY
418                      : : "r" (p_line1), "r" (p_line2),
419                          "r" (p_y1), "r" (p_y2), "r" (p_u), "r" (p_v) ); 
420
421             p_line1 += 8; p_line2 += 8;
422             p_y1 += 4; p_y2 += 4; p_u += 2; p_v += 2;
423 #endif
424         }
425     }
426 }
427
428 /*****************************************************************************
429  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
430  *****************************************************************************/
431 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
432 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
433                                               picture_t *p_dest )
434 {
435     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
436     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
437     u8 *p_u = p_source->U_PIXELS;
438     u8 *p_v = p_source->V_PIXELS;
439
440     int i_x, i_y;
441
442     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
443     {
444         p_line1 = p_line2;
445         p_line2 += p_dest->p->i_pitch;
446
447         p_y1 = p_y2;
448         p_y2 += p_source->p[Y_PLANE].i_pitch;
449
450         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
451         {
452             C_YUV420_Y211( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
453             C_YUV420_Y211( p_line1, p_line2, p_y1, p_y2, p_u, p_v );
454         }
455     }
456 }
457 #endif
458