Split i422->packed YUV and i422->planar YUV. Add i422->YUVA. This still needs some...
[vlc.git] / modules / video_chroma / i422_yuy2.c
1 /*****************************************************************************
2  * i422_yuy2.c : Planar YUV 4:2:2 to Packed YUV conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Damien Fouilleul <damienf@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #include <vlc/vlc.h>
30 #include <vlc_vout.h>
31
32 #include "i422_yuy2.h"
33
34 #define SRC_FOURCC  "I422"
35 #if defined (MODULE_NAME_IS_i422_yuy2)
36 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
37 #else
38 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
39 #endif
40
41 /*****************************************************************************
42  * Local and extern prototypes.
43  *****************************************************************************/
44 static int  Activate ( vlc_object_t * );
45
46 static void I422_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
47 static void I422_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
48 static void I422_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
49 static void I422_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
50 static void I422_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
51 #if defined (MODULE_NAME_IS_i422_yuy2)
52 static void I422_Y211           ( vout_thread_t *, picture_t *, picture_t * );
53 static void I422_Y211           ( vout_thread_t *, picture_t *, picture_t * );
54 #endif
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 vlc_module_begin();
60 #if defined (MODULE_NAME_IS_i422_yuy2)
61     set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
62     set_capability( "chroma", 80 );
63 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
64     set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
65     set_capability( "chroma", 100 );
66     add_requirement( MMX );
67 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
68     set_description( _("SSE2 conversions from " SRC_FOURCC " to " DEST_FOURCC) );
69     set_capability( "chroma", 120 );
70     add_requirement( SSE2 );
71 #endif
72     set_callbacks( Activate, NULL );
73 vlc_module_end();
74
75 /*****************************************************************************
76  * Activate: allocate a chroma function
77  *****************************************************************************
78  * This function allocates and initializes a chroma function
79  *****************************************************************************/
80 static int Activate( vlc_object_t *p_this )
81 {
82     vout_thread_t *p_vout = (vout_thread_t *)p_this;
83
84     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
85     {
86         return -1;
87     }
88
89     switch( p_vout->render.i_chroma )
90     {
91         case VLC_FOURCC('I','4','2','2'):
92             switch( p_vout->output.i_chroma )
93             {
94                 case VLC_FOURCC('Y','U','Y','2'):
95                 case VLC_FOURCC('Y','U','N','V'):
96                     p_vout->chroma.pf_convert = I422_YUY2;
97                     break;
98
99                 case VLC_FOURCC('Y','V','Y','U'):
100                     p_vout->chroma.pf_convert = I422_YVYU;
101                     break;
102
103                 case VLC_FOURCC('U','Y','V','Y'):
104                 case VLC_FOURCC('U','Y','N','V'):
105                 case VLC_FOURCC('Y','4','2','2'):
106                     p_vout->chroma.pf_convert = I422_UYVY;
107                     break;
108
109                 case VLC_FOURCC('I','U','Y','V'):
110                     p_vout->chroma.pf_convert = I422_IUYV;
111                     break;
112
113                 case VLC_FOURCC('c','y','u','v'):
114                     p_vout->chroma.pf_convert = I422_cyuv;
115                     break;
116
117 #if defined (MODULE_NAME_IS_i422_yuy2)
118                 case VLC_FOURCC('Y','2','1','1'):
119                     p_vout->chroma.pf_convert = I422_Y211;
120                     break;
121 #endif
122
123                 default:
124                     return -1;
125             }
126             break;
127
128         default:
129             return -1;
130     }
131     return 0;
132 }
133
134 /* Following functions are local */
135
136 /*****************************************************************************
137  * I422_YUY2: planar YUV 4:2:2 to packed YUY2 4:2:2
138  *****************************************************************************/
139 static void I422_YUY2( vout_thread_t *p_vout, picture_t *p_source,
140                                               picture_t *p_dest )
141 {
142     uint8_t *p_line = p_dest->p->p_pixels;
143     uint8_t *p_y = p_source->Y_PIXELS;
144     uint8_t *p_u = p_source->U_PIXELS;
145     uint8_t *p_v = p_source->V_PIXELS;
146
147     int i_x, i_y;
148
149     const int i_source_margin = p_source->p[0].i_pitch
150                                  - p_source->p[0].i_visible_pitch;
151     const int i_source_margin_c = p_source->p[1].i_pitch
152                                  - p_source->p[1].i_visible_pitch;
153     const int i_dest_margin = p_dest->p->i_pitch
154                                - p_dest->p->i_visible_pitch;
155
156 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
157
158     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
159         ((intptr_t)p_line|(intptr_t)p_y))) )
160     {
161         /* use faster SSE2 aligned fetch and store */
162         for( i_y = p_vout->render.i_height ; i_y-- ; )
163         {
164             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
165             {
166                 SSE2_CALL( SSE2_YUV422_YUYV_ALIGNED );
167             }
168             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
169             {
170                 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
171             }
172             p_y += i_source_margin;
173             p_u += i_source_margin_c;
174             p_v += i_source_margin_c;
175             p_line += i_dest_margin;
176         }
177     }
178     else {
179         /* use slower SSE2 unaligned fetch and store */
180         for( i_y = p_vout->render.i_height ; i_y-- ; )
181         {
182             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
183             {
184                 SSE2_CALL( SSE2_YUV422_YUYV_UNALIGNED );
185             }
186             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
187             {
188                 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
189             }
190             p_y += i_source_margin;
191             p_u += i_source_margin_c;
192             p_v += i_source_margin_c;
193             p_line += i_dest_margin;
194         }
195     }
196     SSE2_END;
197
198 #else
199
200     for( i_y = p_vout->render.i_height ; i_y-- ; )
201     {
202         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
203         {
204 #if defined (MODULE_NAME_IS_i422_yuy2)
205             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
206             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
207             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
208             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
209 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
210             MMX_CALL( MMX_YUV422_YUYV );
211 #endif
212         }
213         for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
214         {
215             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
216         }
217         p_y += i_source_margin;
218         p_u += i_source_margin_c;
219         p_v += i_source_margin_c;
220         p_line += i_dest_margin;
221     }
222 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
223     MMX_END;
224 #endif
225
226 #endif
227 }
228
229 /*****************************************************************************
230  * I422_YVYU: planar YUV 4:2:2 to packed YVYU 4:2:2
231  *****************************************************************************/
232 static void I422_YVYU( vout_thread_t *p_vout, picture_t *p_source,
233                                               picture_t *p_dest )
234 {
235     uint8_t *p_line = p_dest->p->p_pixels;
236     uint8_t *p_y = p_source->Y_PIXELS;
237     uint8_t *p_u = p_source->U_PIXELS;
238     uint8_t *p_v = p_source->V_PIXELS;
239
240     int i_x, i_y;
241
242     const int i_source_margin = p_source->p[0].i_pitch
243                                  - p_source->p[0].i_visible_pitch;
244     const int i_source_margin_c = p_source->p[1].i_pitch
245                                  - p_source->p[1].i_visible_pitch;
246     const int i_dest_margin = p_dest->p->i_pitch
247                                - p_dest->p->i_visible_pitch;
248
249 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
250
251     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
252         ((intptr_t)p_line|(intptr_t)p_y))) )
253     {
254         /* use faster SSE2 aligned fetch and store */
255         for( i_y = p_vout->render.i_height ; i_y-- ; )
256         {
257             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
258             {
259                 SSE2_CALL( SSE2_YUV422_YVYU_ALIGNED );
260             }
261             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
262             {
263                 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
264             }
265             p_y += i_source_margin;
266             p_u += i_source_margin_c;
267             p_v += i_source_margin_c;
268             p_line += i_dest_margin;
269         }
270     }
271     else {
272         /* use slower SSE2 unaligned fetch and store */
273         for( i_y = p_vout->render.i_height ; i_y-- ; )
274         {
275             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
276             {
277                 SSE2_CALL( SSE2_YUV422_YVYU_UNALIGNED );
278             }
279             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
280             {
281                 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
282             }
283             p_y += i_source_margin;
284             p_u += i_source_margin_c;
285             p_v += i_source_margin_c;
286             p_line += i_dest_margin;
287         }
288     }
289     SSE2_END;
290
291 #else
292
293     for( i_y = p_vout->render.i_height ; i_y-- ; )
294     {
295         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
296         {
297 #if defined (MODULE_NAME_IS_i422_yuy2)
298             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
299             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
300             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
301             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
302 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
303             MMX_CALL( MMX_YUV422_YVYU );
304 #endif
305         }
306         for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
307         {
308             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
309         }
310         p_y += i_source_margin;
311         p_u += i_source_margin_c;
312         p_v += i_source_margin_c;
313         p_line += i_dest_margin;
314     }
315 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
316     MMX_END;
317 #endif
318
319 #endif
320 }
321
322 /*****************************************************************************
323  * I422_UYVY: planar YUV 4:2:2 to packed UYVY 4:2:2
324  *****************************************************************************/
325 static void I422_UYVY( vout_thread_t *p_vout, picture_t *p_source,
326                                               picture_t *p_dest )
327 {
328     uint8_t *p_line = p_dest->p->p_pixels;
329     uint8_t *p_y = p_source->Y_PIXELS;
330     uint8_t *p_u = p_source->U_PIXELS;
331     uint8_t *p_v = p_source->V_PIXELS;
332
333     int i_x, i_y;
334
335     const int i_source_margin = p_source->p[0].i_pitch
336                                  - p_source->p[0].i_visible_pitch;
337     const int i_source_margin_c = p_source->p[1].i_pitch
338                                  - p_source->p[1].i_visible_pitch;
339     const int i_dest_margin = p_dest->p->i_pitch
340                                - p_dest->p->i_visible_pitch;
341
342 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
343
344     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
345         ((intptr_t)p_line|(intptr_t)p_y))) )
346     {
347         /* use faster SSE2 aligned fetch and store */
348         for( i_y = p_vout->render.i_height ; i_y-- ; )
349         {
350             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
351             {
352                 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
353             }
354             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
355             {
356                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
357             }
358             p_y += i_source_margin;
359             p_u += i_source_margin_c;
360             p_v += i_source_margin_c;
361             p_line += i_dest_margin;
362         }
363     }
364     else {
365         /* use slower SSE2 unaligned fetch and store */
366         for( i_y = p_vout->render.i_height ; i_y-- ; )
367         {
368             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
369             {
370                 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
371             }
372             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
373             {
374                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
375             }
376             p_y += i_source_margin;
377             p_u += i_source_margin_c;
378             p_v += i_source_margin_c;
379             p_line += i_dest_margin;
380         }
381     }
382     SSE2_END;
383
384 #else
385
386     for( i_y = p_vout->render.i_height ; i_y-- ; )
387     {
388         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
389         {
390 #if defined (MODULE_NAME_IS_i422_yuy2)
391             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
392             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
393             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
394             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
395 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
396             MMX_CALL( MMX_YUV422_UYVY );
397 #endif
398         }
399         for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
400         {
401             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
402         }
403         p_y += i_source_margin;
404         p_u += i_source_margin_c;
405         p_v += i_source_margin_c;
406         p_line += i_dest_margin;
407     }
408 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
409     MMX_END;
410 #endif
411
412 #endif
413 }
414
415 /*****************************************************************************
416  * I422_IUYV: planar YUV 4:2:2 to interleaved packed IUYV 4:2:2
417  *****************************************************************************/
418 static void I422_IUYV( vout_thread_t *p_vout, picture_t *p_source,
419                                               picture_t *p_dest )
420 {
421     /* FIXME: TODO ! */
422     msg_Err( p_vout, "I422_IUYV unimplemented, please harass <sam@zoy.org>" );
423 }
424
425 /*****************************************************************************
426  * I422_cyuv: planar YUV 4:2:2 to upside-down packed UYVY 4:2:2
427  *****************************************************************************/
428 static void I422_cyuv( vout_thread_t *p_vout, picture_t *p_source,
429                                               picture_t *p_dest )
430 {
431     uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
432     uint8_t *p_y = p_source->Y_PIXELS;
433     uint8_t *p_u = p_source->U_PIXELS;
434     uint8_t *p_v = p_source->V_PIXELS;
435
436     int i_x, i_y;
437
438     const int i_source_margin = p_source->p[0].i_pitch
439                                  - p_source->p[0].i_visible_pitch;
440     const int i_source_margin_c = p_source->p[1].i_pitch
441                                  - p_source->p[1].i_visible_pitch;
442     const int i_dest_margin = p_dest->p->i_pitch
443                                - p_dest->p->i_visible_pitch;
444
445 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
446
447     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
448         ((intptr_t)p_line|(intptr_t)p_y))) )
449     {
450         /* use faster SSE2 aligned fetch and store */
451         for( i_y = p_vout->render.i_height ; i_y-- ; )
452         {
453             p_line -= 2 * p_dest->p->i_pitch;
454
455             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
456             {
457                 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
458             }
459             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
460             {
461                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
462             }
463             p_y += i_source_margin;
464             p_u += i_source_margin_c;
465             p_v += i_source_margin_c;
466             p_line += i_dest_margin;
467         }
468     }
469     else {
470         /* use slower SSE2 unaligned fetch and store */
471         for( i_y = p_vout->render.i_height ; i_y-- ; )
472         {
473             p_line -= 2 * p_dest->p->i_pitch;
474
475             for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
476             {
477                 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
478             }
479             for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
480             {
481                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
482             }
483             p_y += i_source_margin;
484             p_u += i_source_margin_c;
485             p_v += i_source_margin_c;
486             p_line += i_dest_margin;
487         }
488     }
489     SSE2_END;
490
491 #else
492
493     for( i_y = p_vout->render.i_height ; i_y-- ; )
494     {
495         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
496         {
497             p_line -= 2 * p_dest->p->i_pitch;
498
499 #if defined (MODULE_NAME_IS_i422_yuy2)
500             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
501             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
502             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
503             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
504 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
505             MMX_CALL( MMX_YUV422_UYVY );
506 #endif
507         }
508         p_y += i_source_margin;
509         p_u += i_source_margin_c;
510         p_v += i_source_margin_c;
511         p_line += i_dest_margin;
512     }
513 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
514     MMX_END;
515 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
516     SSE2_END;
517 #endif
518
519 #endif
520 }
521
522 /*****************************************************************************
523  * I422_Y211: planar YUV 4:2:2 to packed YUYV 2:1:1
524  *****************************************************************************/
525 #if defined (MODULE_NAME_IS_i422_yuy2)
526 static void I422_Y211( vout_thread_t *p_vout, picture_t *p_source,
527                                               picture_t *p_dest )
528 {
529     uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
530     uint8_t *p_y = p_source->Y_PIXELS;
531     uint8_t *p_u = p_source->U_PIXELS;
532     uint8_t *p_v = p_source->V_PIXELS;
533
534     int i_x, i_y;
535
536     for( i_y = p_vout->render.i_height ; i_y-- ; )
537     {
538         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
539         {
540             C_YUV422_Y211( p_line, p_y, p_u, p_v );
541             C_YUV422_Y211( p_line, p_y, p_u, p_v );
542         }
543     }
544 }
545 #endif