Move SSE2 chromas to sse2/
[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 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
36
37 #include "i422_yuy2.h"
38
39 #define SRC_FOURCC  "I422"
40 #if defined (MODULE_NAME_IS_i422_yuy2)
41 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
42 #else
43 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
44 #endif
45
46 /*****************************************************************************
47  * Local and extern prototypes.
48  *****************************************************************************/
49 static int  Activate ( vlc_object_t * );
50
51 static void I422_YUY2               ( filter_t *, picture_t *, picture_t * );
52 static void I422_YVYU               ( filter_t *, picture_t *, picture_t * );
53 static void I422_UYVY               ( filter_t *, picture_t *, picture_t * );
54 static void I422_IUYV               ( filter_t *, picture_t *, picture_t * );
55 static void I422_cyuv               ( filter_t *, picture_t *, picture_t * );
56 static picture_t *I422_YUY2_Filter  ( filter_t *, picture_t * );
57 static picture_t *I422_YVYU_Filter  ( filter_t *, picture_t * );
58 static picture_t *I422_UYVY_Filter  ( filter_t *, picture_t * );
59 static picture_t *I422_IUYV_Filter  ( filter_t *, picture_t * );
60 static picture_t *I422_cyuv_Filter  ( filter_t *, picture_t * );
61 #if defined (MODULE_NAME_IS_i422_yuy2)
62 static void I422_Y211               ( filter_t *, picture_t *, picture_t * );
63 static picture_t *I422_Y211_Filter  ( filter_t *, picture_t * );
64 #endif
65
66 /*****************************************************************************
67  * Module descriptor
68  *****************************************************************************/
69 vlc_module_begin ()
70 #if defined (MODULE_NAME_IS_i422_yuy2)
71     set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) )
72     set_capability( "video filter2", 80 )
73 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
74     set_description( N_("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) )
75     set_capability( "video filter2", 100 )
76 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
77     set_description( N_("SSE2 conversions from " SRC_FOURCC " to " DEST_FOURCC) )
78     set_capability( "video filter2", 120 )
79 #endif
80     set_callbacks( Activate, NULL )
81 vlc_module_end ()
82
83 /*****************************************************************************
84  * Activate: allocate a chroma function
85  *****************************************************************************
86  * This function allocates and initializes a chroma function
87  *****************************************************************************/
88 static int Activate( vlc_object_t *p_this )
89 {
90     filter_t *p_filter = (filter_t *)p_this;
91
92     if( p_filter->fmt_in.video.i_width & 1
93      || p_filter->fmt_in.video.i_height & 1 )
94     {
95         return -1;
96     }
97
98     switch( p_filter->fmt_in.video.i_chroma )
99     {
100         case VLC_CODEC_I422:
101             switch( p_filter->fmt_out.video.i_chroma )
102             {
103                 case VLC_CODEC_YUYV:
104                     p_filter->pf_video_filter = I422_YUY2_Filter;
105                     break;
106
107                 case VLC_CODEC_YVYU:
108                     p_filter->pf_video_filter = I422_YVYU_Filter;
109                     break;
110
111                 case VLC_CODEC_UYVY:
112                     p_filter->pf_video_filter = I422_UYVY_Filter;
113                     break;
114
115                     p_filter->pf_video_filter = I422_IUYV_Filter;
116                     break;
117
118                 case VLC_CODEC_CYUV:
119                     p_filter->pf_video_filter = I422_cyuv_Filter;
120                     break;
121
122 #if defined (MODULE_NAME_IS_i422_yuy2)
123                 case VLC_CODEC_Y211:
124                     p_filter->pf_video_filter = I422_Y211_Filter;
125                     break;
126 #endif
127
128                 default:
129                     return -1;
130             }
131             break;
132
133         default:
134             return -1;
135     }
136     return 0;
137 }
138
139 /* Following functions are local */
140
141 VIDEO_FILTER_WRAPPER( I422_YUY2 )
142 VIDEO_FILTER_WRAPPER( I422_YVYU )
143 VIDEO_FILTER_WRAPPER( I422_UYVY )
144 VIDEO_FILTER_WRAPPER( I422_IUYV )
145 VIDEO_FILTER_WRAPPER( I422_cyuv )
146 #if defined (MODULE_NAME_IS_i422_yuy2)
147 VIDEO_FILTER_WRAPPER( I422_Y211 )
148 #endif
149
150 /*****************************************************************************
151  * I422_YUY2: planar YUV 4:2:2 to packed YUY2 4:2:2
152  *****************************************************************************/
153 static void I422_YUY2( filter_t *p_filter, picture_t *p_source,
154                                            picture_t *p_dest )
155 {
156     uint8_t *p_line = p_dest->p->p_pixels;
157     uint8_t *p_y = p_source->Y_PIXELS;
158     uint8_t *p_u = p_source->U_PIXELS;
159     uint8_t *p_v = p_source->V_PIXELS;
160
161     int i_x, i_y;
162
163     const int i_source_margin = p_source->p[0].i_pitch
164                                  - p_source->p[0].i_visible_pitch;
165     const int i_source_margin_c = p_source->p[1].i_pitch
166                                  - p_source->p[1].i_visible_pitch;
167     const int i_dest_margin = p_dest->p->i_pitch
168                                - p_dest->p->i_visible_pitch;
169
170 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
171
172     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
173         ((intptr_t)p_line|(intptr_t)p_y))) )
174     {
175         /* use faster SSE2 aligned fetch and store */
176         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
177         {
178             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
179             {
180                 SSE2_CALL( SSE2_YUV422_YUYV_ALIGNED );
181             }
182             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
183             {
184                 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
185             }
186             p_y += i_source_margin;
187             p_u += i_source_margin_c;
188             p_v += i_source_margin_c;
189             p_line += i_dest_margin;
190         }
191     }
192     else {
193         /* use slower SSE2 unaligned fetch and store */
194         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
195         {
196             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
197             {
198                 SSE2_CALL( SSE2_YUV422_YUYV_UNALIGNED );
199             }
200             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
201             {
202                 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
203             }
204             p_y += i_source_margin;
205             p_u += i_source_margin_c;
206             p_v += i_source_margin_c;
207             p_line += i_dest_margin;
208         }
209     }
210     SSE2_END;
211
212 #else
213
214     for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
215     {
216         for( i_x = p_filter->fmt_in.video.i_width / 8 ; i_x-- ; )
217         {
218 #if defined (MODULE_NAME_IS_i422_yuy2)
219             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
220             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
221             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
222             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
223 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
224             MMX_CALL( MMX_YUV422_YUYV );
225 #endif
226         }
227         for( i_x = ( p_filter->fmt_in.video.i_width % 8 ) / 2; i_x-- ; )
228         {
229             C_YUV422_YUYV( p_line, p_y, p_u, p_v );
230         }
231         p_y += i_source_margin;
232         p_u += i_source_margin_c;
233         p_v += i_source_margin_c;
234         p_line += i_dest_margin;
235     }
236 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
237     MMX_END;
238 #endif
239
240 #endif
241 }
242
243 /*****************************************************************************
244  * I422_YVYU: planar YUV 4:2:2 to packed YVYU 4:2:2
245  *****************************************************************************/
246 static void I422_YVYU( filter_t *p_filter, picture_t *p_source,
247                                            picture_t *p_dest )
248 {
249     uint8_t *p_line = p_dest->p->p_pixels;
250     uint8_t *p_y = p_source->Y_PIXELS;
251     uint8_t *p_u = p_source->U_PIXELS;
252     uint8_t *p_v = p_source->V_PIXELS;
253
254     int i_x, i_y;
255
256     const int i_source_margin = p_source->p[0].i_pitch
257                                  - p_source->p[0].i_visible_pitch;
258     const int i_source_margin_c = p_source->p[1].i_pitch
259                                  - p_source->p[1].i_visible_pitch;
260     const int i_dest_margin = p_dest->p->i_pitch
261                                - p_dest->p->i_visible_pitch;
262
263 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
264
265     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
266         ((intptr_t)p_line|(intptr_t)p_y))) )
267     {
268         /* use faster SSE2 aligned fetch and store */
269         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
270         {
271             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
272             {
273                 SSE2_CALL( SSE2_YUV422_YVYU_ALIGNED );
274             }
275             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
276             {
277                 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
278             }
279             p_y += i_source_margin;
280             p_u += i_source_margin_c;
281             p_v += i_source_margin_c;
282             p_line += i_dest_margin;
283         }
284     }
285     else {
286         /* use slower SSE2 unaligned fetch and store */
287         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
288         {
289             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
290             {
291                 SSE2_CALL( SSE2_YUV422_YVYU_UNALIGNED );
292             }
293             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
294             {
295                 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
296             }
297             p_y += i_source_margin;
298             p_u += i_source_margin_c;
299             p_v += i_source_margin_c;
300             p_line += i_dest_margin;
301         }
302     }
303     SSE2_END;
304
305 #else
306
307     for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
308     {
309         for( i_x = p_filter->fmt_in.video.i_width / 8 ; i_x-- ; )
310         {
311 #if defined (MODULE_NAME_IS_i422_yuy2)
312             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
313             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
314             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
315             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
316 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
317             MMX_CALL( MMX_YUV422_YVYU );
318 #endif
319         }
320         for( i_x = ( p_filter->fmt_in.video.i_width % 8 ) / 2; i_x-- ; )
321         {
322             C_YUV422_YVYU( p_line, p_y, p_u, p_v );
323         }
324         p_y += i_source_margin;
325         p_u += i_source_margin_c;
326         p_v += i_source_margin_c;
327         p_line += i_dest_margin;
328     }
329 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
330     MMX_END;
331 #endif
332
333 #endif
334 }
335
336 /*****************************************************************************
337  * I422_UYVY: planar YUV 4:2:2 to packed UYVY 4:2:2
338  *****************************************************************************/
339 static void I422_UYVY( filter_t *p_filter, picture_t *p_source,
340                                            picture_t *p_dest )
341 {
342     uint8_t *p_line = p_dest->p->p_pixels;
343     uint8_t *p_y = p_source->Y_PIXELS;
344     uint8_t *p_u = p_source->U_PIXELS;
345     uint8_t *p_v = p_source->V_PIXELS;
346
347     int i_x, i_y;
348
349     const int i_source_margin = p_source->p[0].i_pitch
350                                  - p_source->p[0].i_visible_pitch;
351     const int i_source_margin_c = p_source->p[1].i_pitch
352                                  - p_source->p[1].i_visible_pitch;
353     const int i_dest_margin = p_dest->p->i_pitch
354                                - p_dest->p->i_visible_pitch;
355
356 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
357
358     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
359         ((intptr_t)p_line|(intptr_t)p_y))) )
360     {
361         /* use faster SSE2 aligned fetch and store */
362         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
363         {
364             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
365             {
366                 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
367             }
368             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
369             {
370                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
371             }
372             p_y += i_source_margin;
373             p_u += i_source_margin_c;
374             p_v += i_source_margin_c;
375             p_line += i_dest_margin;
376         }
377     }
378     else {
379         /* use slower SSE2 unaligned fetch and store */
380         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
381         {
382             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
383             {
384                 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
385             }
386             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
387             {
388                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
389             }
390             p_y += i_source_margin;
391             p_u += i_source_margin_c;
392             p_v += i_source_margin_c;
393             p_line += i_dest_margin;
394         }
395     }
396     SSE2_END;
397
398 #else
399
400     for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
401     {
402         for( i_x = p_filter->fmt_in.video.i_width / 8 ; i_x-- ; )
403         {
404 #if defined (MODULE_NAME_IS_i422_yuy2)
405             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
406             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
407             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
408             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
409 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
410             MMX_CALL( MMX_YUV422_UYVY );
411 #endif
412         }
413         for( i_x = ( p_filter->fmt_in.video.i_width % 8 ) / 2; i_x-- ; )
414         {
415             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
416         }
417         p_y += i_source_margin;
418         p_u += i_source_margin_c;
419         p_v += i_source_margin_c;
420         p_line += i_dest_margin;
421     }
422 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
423     MMX_END;
424 #endif
425
426 #endif
427 }
428
429 /*****************************************************************************
430  * I422_IUYV: planar YUV 4:2:2 to interleaved packed IUYV 4:2:2
431  *****************************************************************************/
432 static void I422_IUYV( filter_t *p_filter, picture_t *p_source,
433                                            picture_t *p_dest )
434 {
435     VLC_UNUSED(p_source); VLC_UNUSED(p_dest);
436     /* FIXME: TODO ! */
437     msg_Err( p_filter, "I422_IUYV unimplemented, please harass <sam@zoy.org>" );
438 }
439
440 /*****************************************************************************
441  * I422_cyuv: planar YUV 4:2:2 to upside-down packed UYVY 4:2:2
442  *****************************************************************************/
443 static void I422_cyuv( filter_t *p_filter, picture_t *p_source,
444                                            picture_t *p_dest )
445 {
446     uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
447     uint8_t *p_y = p_source->Y_PIXELS;
448     uint8_t *p_u = p_source->U_PIXELS;
449     uint8_t *p_v = p_source->V_PIXELS;
450
451     int i_x, i_y;
452
453     const int i_source_margin = p_source->p[0].i_pitch
454                                  - p_source->p[0].i_visible_pitch;
455     const int i_source_margin_c = p_source->p[1].i_pitch
456                                  - p_source->p[1].i_visible_pitch;
457     const int i_dest_margin = p_dest->p->i_pitch
458                                - p_dest->p->i_visible_pitch;
459
460 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
461
462     if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
463         ((intptr_t)p_line|(intptr_t)p_y))) )
464     {
465         /* use faster SSE2 aligned fetch and store */
466         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
467         {
468             p_line -= 2 * p_dest->p->i_pitch;
469
470             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
471             {
472                 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
473             }
474             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
475             {
476                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
477             }
478             p_y += i_source_margin;
479             p_u += i_source_margin_c;
480             p_v += i_source_margin_c;
481             p_line += i_dest_margin;
482         }
483     }
484     else {
485         /* use slower SSE2 unaligned fetch and store */
486         for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
487         {
488             p_line -= 2 * p_dest->p->i_pitch;
489
490             for( i_x = p_filter->fmt_in.video.i_width / 16 ; i_x-- ; )
491             {
492                 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
493             }
494             for( i_x = ( p_filter->fmt_in.video.i_width % 16 ) / 2; i_x-- ; )
495             {
496                 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
497             }
498             p_y += i_source_margin;
499             p_u += i_source_margin_c;
500             p_v += i_source_margin_c;
501             p_line += i_dest_margin;
502         }
503     }
504     SSE2_END;
505
506 #else
507
508     for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
509     {
510         for( i_x = p_filter->fmt_in.video.i_width / 8 ; i_x-- ; )
511         {
512             p_line -= 2 * p_dest->p->i_pitch;
513
514 #if defined (MODULE_NAME_IS_i422_yuy2)
515             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
516             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
517             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
518             C_YUV422_UYVY( p_line, p_y, p_u, p_v );
519 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
520             MMX_CALL( MMX_YUV422_UYVY );
521 #endif
522         }
523         p_y += i_source_margin;
524         p_u += i_source_margin_c;
525         p_v += i_source_margin_c;
526         p_line += i_dest_margin;
527     }
528 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
529     MMX_END;
530 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
531     SSE2_END;
532 #endif
533
534 #endif
535 }
536
537 /*****************************************************************************
538  * I422_Y211: planar YUV 4:2:2 to packed YUYV 2:1:1
539  *****************************************************************************/
540 #if defined (MODULE_NAME_IS_i422_yuy2)
541 static void I422_Y211( filter_t *p_filter, picture_t *p_source,
542                                            picture_t *p_dest )
543 {
544     uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
545     uint8_t *p_y = p_source->Y_PIXELS;
546     uint8_t *p_u = p_source->U_PIXELS;
547     uint8_t *p_v = p_source->V_PIXELS;
548
549     int i_x, i_y;
550
551     for( i_y = p_filter->fmt_in.video.i_height ; i_y-- ; )
552     {
553         for( i_x = p_filter->fmt_in.video.i_width / 8 ; i_x-- ; )
554         {
555             C_YUV422_Y211( p_line, p_y, p_u, p_v );
556             C_YUV422_Y211( p_line, p_y, p_u, p_v );
557         }
558     }
559 }
560 #endif