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