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