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