]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_yuy2.c
* configure.ac:
[vlc] / modules / video_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$
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 <string.h>                                            /* strerror() */
28 #include <stdlib.h>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32
33 #ifdef HAVE_ALTIVEC_H
34 #   include <altivec.h>
35 #endif
36
37 #include "i420_yuy2.h"
38
39 #define SRC_FOURCC  "I420,IYUV,YV12"
40
41 #if defined (MODULE_NAME_IS_i420_yuy2)
42 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
43 #elif defined (MODULE_NAME_IS_i420_yuy2_mmx)
44 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
45 #elif defined (MODULE_NAME_IS_i420_yuy2_altivec)
46 #    define DEST_FOURCC "YUY2,YUNV"
47 #endif
48
49 /*****************************************************************************
50  * Local and extern prototypes.
51  *****************************************************************************/
52 static int  Activate ( vlc_object_t * );
53
54 static void I420_YUY2           ( vout_thread_t *, picture_t *, picture_t * );
55 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
56 static void I420_YVYU           ( vout_thread_t *, picture_t *, picture_t * );
57 static void I420_UYVY           ( vout_thread_t *, picture_t *, picture_t * );
58 static void I420_IUYV           ( vout_thread_t *, picture_t *, picture_t * );
59 static void I420_cyuv           ( vout_thread_t *, picture_t *, picture_t * );
60 #endif
61 #if defined (MODULE_NAME_IS_i420_yuy2)
62 static void I420_Y211           ( vout_thread_t *, picture_t *, picture_t * );
63 #endif
64
65 #ifdef MODULE_NAME_IS_i420_yuy2_mmx
66 static uint64_t i_00ffw;
67 static uint64_t i_80w;
68 #endif
69
70 /*****************************************************************************
71  * Module descriptor.
72  *****************************************************************************/
73 vlc_module_begin();
74 #if defined (MODULE_NAME_IS_i420_yuy2)
75     set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
76     set_capability( "chroma", 80 );
77 #elif defined (MODULE_NAME_IS_i420_yuy2_mmx)
78     set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
79     set_capability( "chroma", 100 );
80     add_requirement( MMX );
81     /* Initialize MMX-specific constants */
82     i_00ffw = 0x00ff00ff00ff00ffULL;
83     i_80w   = 0x0000000080808080ULL;
84 #elif defined (MODULE_NAME_IS_i420_yuy2_altivec)
85     set_description(
86             _("Altivec conversions from " SRC_FOURCC " to " DEST_FOURCC) );
87     set_capability( "chroma", 100 );
88     add_requirement( ALTIVEC );
89 #endif
90     set_callbacks( Activate, NULL );
91 vlc_module_end();
92
93 /*****************************************************************************
94  * Activate: allocate a chroma function
95  *****************************************************************************
96  * This function allocates and initializes a chroma function
97  *****************************************************************************/
98 static int Activate( vlc_object_t *p_this )
99 {
100     vout_thread_t *p_vout = (vout_thread_t *)p_this;
101
102     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
103     {
104         return -1;
105     }
106
107     switch( p_vout->render.i_chroma )
108     {
109         case VLC_FOURCC('Y','V','1','2'):
110         case VLC_FOURCC('I','4','2','0'):
111         case VLC_FOURCC('I','Y','U','V'):
112             switch( p_vout->output.i_chroma )
113             {
114                 case VLC_FOURCC('Y','U','Y','2'):
115                 case VLC_FOURCC('Y','U','N','V'):
116                     p_vout->chroma.pf_convert = I420_YUY2;
117                     break;
118
119 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
120                 case VLC_FOURCC('Y','V','Y','U'):
121                     p_vout->chroma.pf_convert = I420_YVYU;
122                     break;
123
124                 case VLC_FOURCC('U','Y','V','Y'):
125                 case VLC_FOURCC('U','Y','N','V'):
126                 case VLC_FOURCC('Y','4','2','2'):
127                     p_vout->chroma.pf_convert = I420_UYVY;
128                     break;
129
130                 case VLC_FOURCC('I','U','Y','V'):
131                     p_vout->chroma.pf_convert = I420_IUYV;
132                     break;
133
134                 case VLC_FOURCC('c','y','u','v'):
135                     p_vout->chroma.pf_convert = I420_cyuv;
136                     break;
137 #endif
138
139 #if defined (MODULE_NAME_IS_i420_yuy2)
140                 case VLC_FOURCC('Y','2','1','1'):
141                     p_vout->chroma.pf_convert = I420_Y211;
142                     break;
143 #endif
144
145                 default:
146                     return -1;
147             }
148             break;
149
150         default:
151             return -1;
152     }
153
154     return 0;
155 }
156
157 /* Following functions are local */
158
159 /*****************************************************************************
160  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
161  *****************************************************************************/
162 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
163                                               picture_t *p_dest )
164 {
165     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
166     uint8_t *p_y1, *p_y2 = 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 #if defined (MODULE_NAME_IS_i420_yuy2_altivec)
173 #define VEC_NEXT_LINES( ) \
174     p_line1  = p_line2; \
175     p_line2 += p_dest->p->i_pitch; \
176     p_y1     = p_y2; \
177     p_y2    += p_source->p[Y_PLANE].i_pitch;
178
179 #define VEC_LOAD_UV( ) \
180     u_vec = vec_ld( 0, p_u ); p_u += 16; \
181     v_vec = vec_ld( 0, p_v ); p_v += 16;
182
183 #define VEC_MERGE( a ) \
184     uv_vec = a( u_vec, v_vec ); \
185     y_vec = vec_ld( 0, p_y1 ); p_y1 += 16; \
186     vec_st( vec_mergeh( y_vec, uv_vec ), 0, p_line1 ); p_line1 += 16; \
187     vec_st( vec_mergel( y_vec, uv_vec ), 0, p_line1 ); p_line1 += 16; \
188     y_vec = vec_ld( 0, p_y2 ); p_y2 += 16; \
189     vec_st( vec_mergeh( y_vec, uv_vec ), 0, p_line2 ); p_line2 += 16; \
190     vec_st( vec_mergel( y_vec, uv_vec ), 0, p_line2 ); p_line2 += 16;
191
192     vector unsigned char u_vec;
193     vector unsigned char v_vec;
194     vector unsigned char uv_vec;
195     vector unsigned char y_vec;
196
197     if( !( ( p_vout->render.i_width % 32 ) |
198            ( p_vout->render.i_height % 2 ) ) )
199     {
200         /* Width is a multiple of 32, we take 2 lines at a time */
201         for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
202         {
203             VEC_NEXT_LINES( );
204             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
205             {
206                 VEC_LOAD_UV( );
207                 VEC_MERGE( vec_mergeh );
208                 VEC_MERGE( vec_mergel );
209             }
210         }
211     }
212     else if( !( ( p_vout->render.i_width % 16 ) |
213                 ( p_vout->render.i_height % 4 ) ) )
214     {
215         /* Width is only a multiple of 16, we take 4 lines at a time */
216         for( i_y = p_vout->render.i_height / 4 ; i_y-- ; )
217         {
218             /* Line 1 and 2, pixels 0 to ( width - 16 ) */
219             VEC_NEXT_LINES( );
220             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
221             {
222                 VEC_LOAD_UV( );
223                 VEC_MERGE( vec_mergeh );
224                 VEC_MERGE( vec_mergel );
225             }
226
227             /* Line 1 and 2, pixels ( width - 16 ) to ( width ) */
228             VEC_LOAD_UV( );
229             VEC_MERGE( vec_mergeh );
230
231             /* Line 3 and 4, pixels 0 to 16 */
232             VEC_NEXT_LINES( );
233             VEC_MERGE( vec_mergel );
234
235             /* Line 3 and 4, pixels 16 to ( width ) */
236             for( i_x = p_vout->render.i_width / 32 ; i_x-- ; )
237             {
238                 VEC_LOAD_UV( );
239                 VEC_MERGE( vec_mergeh );
240                 VEC_MERGE( vec_mergel );
241             }
242         }
243     }
244     else
245     {
246         /* Crap, use the C version */
247 #undef VEC_NEXT_LINES
248 #undef VEC_LOAD_UV
249 #undef VEC_MERGE
250 #endif
251
252     const int i_source_margin = p_source->p->i_pitch
253                                  - p_source->p->i_visible_pitch;
254     const int i_dest_margin = p_dest->p->i_pitch
255                                - p_dest->p->i_visible_pitch;
256
257     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
258     {
259         p_line1 = p_line2;
260         p_line2 += p_dest->p->i_pitch;
261
262         p_y1 = p_y2;
263         p_y2 += p_source->p[Y_PLANE].i_pitch;
264
265         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
266         {
267 #if !defined (MODULE_NAME_IS_i420_yuy2_mmx)
268             C_YUV420_YUYV( );
269             C_YUV420_YUYV( );
270             C_YUV420_YUYV( );
271             C_YUV420_YUYV( );
272 #else
273             MMX_CALL( MMX_YUV420_YUYV );
274 #endif
275         }
276
277         p_y1 += i_source_margin;
278         p_y2 += i_source_margin;
279         p_line1 += i_dest_margin;
280         p_line2 += i_dest_margin;
281     }
282
283 #if defined (MODULE_NAME_IS_i420_yuy2_altivec)
284     }
285 #endif
286 }
287
288 /*****************************************************************************
289  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
290  *****************************************************************************/
291 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
292 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
293                                               picture_t *p_dest )
294 {
295     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
296     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
297     uint8_t *p_u = p_source->U_PIXELS;
298     uint8_t *p_v = p_source->V_PIXELS;
299
300     int i_x, i_y;
301
302     const int i_source_margin = p_source->p->i_pitch
303                                  - p_source->p->i_visible_pitch;
304     const int i_dest_margin = p_dest->p->i_pitch
305                                - p_dest->p->i_visible_pitch;
306
307     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
308     {
309         p_line1 = p_line2;
310         p_line2 += p_dest->p->i_pitch;
311
312         p_y1 = p_y2;
313         p_y2 += p_source->p[Y_PLANE].i_pitch;
314
315         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
316         {
317 #if defined (MODULE_NAME_IS_i420_yuy2)
318             C_YUV420_YVYU( );
319             C_YUV420_YVYU( );
320             C_YUV420_YVYU( );
321             C_YUV420_YVYU( );
322 #else
323             MMX_CALL( MMX_YUV420_YVYU );
324 #endif
325         }
326
327         p_y1 += i_source_margin;
328         p_y2 += i_source_margin;
329         p_line1 += i_dest_margin;
330         p_line2 += i_dest_margin;
331     }
332 }
333
334 /*****************************************************************************
335  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
336  *****************************************************************************/
337 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
338                                               picture_t *p_dest )
339 {
340     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
341     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
342     uint8_t *p_u = p_source->U_PIXELS;
343     uint8_t *p_v = p_source->V_PIXELS;
344
345     int i_x, i_y;
346
347     const int i_source_margin = p_source->p->i_pitch
348                                  - p_source->p->i_visible_pitch;
349     const int i_dest_margin = p_dest->p->i_pitch
350                                - p_dest->p->i_visible_pitch;
351
352     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
353     {
354         p_line1 = p_line2;
355         p_line2 += p_dest->p->i_pitch;
356
357         p_y1 = p_y2;
358         p_y2 += p_source->p[Y_PLANE].i_pitch;
359
360         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
361         {
362 #if defined (MODULE_NAME_IS_i420_yuy2)
363             C_YUV420_UYVY( );
364             C_YUV420_UYVY( );
365             C_YUV420_UYVY( );
366             C_YUV420_UYVY( );
367 #else
368             MMX_CALL( MMX_YUV420_UYVY );
369 #endif
370         }
371
372         p_y1 += i_source_margin;
373         p_y2 += i_source_margin;
374         p_line1 += i_dest_margin;
375         p_line2 += i_dest_margin;
376     }
377 }
378
379 /*****************************************************************************
380  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
381  *****************************************************************************/
382 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
383                                               picture_t *p_dest )
384 {
385     /* FIXME: TODO ! */
386     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
387 }
388
389 /*****************************************************************************
390  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
391  *****************************************************************************/
392 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
393                                               picture_t *p_dest )
394 {
395     uint8_t *p_line1 = p_dest->p->p_pixels +
396                        p_dest->p->i_lines * p_dest->p->i_pitch
397                        + p_dest->p->i_pitch;
398     uint8_t *p_line2 = p_dest->p->p_pixels +
399                        p_dest->p->i_lines * p_dest->p->i_pitch;
400     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
401     uint8_t *p_u = p_source->U_PIXELS;
402     uint8_t *p_v = p_source->V_PIXELS;
403
404     int i_x, i_y;
405
406     const int i_source_margin = p_source->p->i_pitch
407                                  - p_source->p->i_visible_pitch;
408     const int i_dest_margin = p_dest->p->i_pitch
409                                - p_dest->p->i_visible_pitch;
410
411     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
412     {
413         p_line1 -= 3 * p_dest->p->i_pitch;
414         p_line2 -= 3 * p_dest->p->i_pitch;
415
416         p_y1 = p_y2;
417         p_y2 += p_source->p[Y_PLANE].i_pitch;
418
419         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
420         {
421 #if defined (MODULE_NAME_IS_i420_yuy2)
422             C_YUV420_UYVY( );
423             C_YUV420_UYVY( );
424             C_YUV420_UYVY( );
425             C_YUV420_UYVY( );
426 #else
427             MMX_CALL( MMX_YUV420_UYVY );
428 #endif
429         }
430
431         p_y1 += i_source_margin;
432         p_y2 += i_source_margin;
433         p_line1 += i_dest_margin;
434         p_line2 += i_dest_margin;
435     }
436 }
437 #endif // !defined (MODULE_NAME_IS_i420_yuy2_altivec)
438
439 /*****************************************************************************
440  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
441  *****************************************************************************/
442 #if defined (MODULE_NAME_IS_i420_yuy2)
443 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
444                                               picture_t *p_dest )
445 {
446     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
447     uint8_t *p_y1, *p_y2 = 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->i_pitch
454                                  - p_source->p->i_visible_pitch;
455     const int i_dest_margin = p_dest->p->i_pitch
456                                - p_dest->p->i_visible_pitch;
457
458     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
459     {
460         p_line1 = p_line2;
461         p_line2 += p_dest->p->i_pitch;
462
463         p_y1 = p_y2;
464         p_y2 += p_source->p[Y_PLANE].i_pitch;
465
466         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
467         {
468             C_YUV420_Y211( );
469             C_YUV420_Y211( );
470         }
471
472         p_y1 += i_source_margin;
473         p_y2 += i_source_margin;
474         p_line1 += i_dest_margin;
475         p_line2 += i_dest_margin;
476     }
477 }
478 #endif
479