]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_yuy2.c
* ALL: use i_visible_lines in plane_t.
[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 #if !defined (MODULE_NAME_IS_i420_yuy2_mmx)
266         for( i_x = p_vout->render.i_width / 2 ; i_x-- ; )
267         {
268             C_YUV420_YUYV( );
269         }
270 #else
271         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
272         {
273             MMX_CALL( MMX_YUV420_YUYV );
274         }
275         for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
276         {
277             C_YUV420_YUYV( );
278         }
279 #endif
280
281         p_y1 += i_source_margin;
282         p_y2 += i_source_margin;
283         p_line1 += i_dest_margin;
284         p_line2 += i_dest_margin;
285     }
286
287 #if defined (MODULE_NAME_IS_i420_yuy2_altivec)
288     }
289 #endif
290 }
291
292 /*****************************************************************************
293  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
294  *****************************************************************************/
295 #if !defined (MODULE_NAME_IS_i420_yuy2_altivec)
296 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
297                                               picture_t *p_dest )
298 {
299     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
300     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
301     uint8_t *p_u = p_source->U_PIXELS;
302     uint8_t *p_v = p_source->V_PIXELS;
303
304     int i_x, i_y;
305
306     const int i_source_margin = p_source->p->i_pitch
307                                  - p_source->p->i_visible_pitch;
308     const int i_dest_margin = p_dest->p->i_pitch
309                                - p_dest->p->i_visible_pitch;
310
311     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
312     {
313         p_line1 = p_line2;
314         p_line2 += p_dest->p->i_pitch;
315
316         p_y1 = p_y2;
317         p_y2 += p_source->p[Y_PLANE].i_pitch;
318
319         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
320         {
321 #if defined (MODULE_NAME_IS_i420_yuy2)
322             C_YUV420_YVYU( );
323             C_YUV420_YVYU( );
324             C_YUV420_YVYU( );
325             C_YUV420_YVYU( );
326 #else
327             MMX_CALL( MMX_YUV420_YVYU );
328 #endif
329         }
330
331         p_y1 += i_source_margin;
332         p_y2 += i_source_margin;
333         p_line1 += i_dest_margin;
334         p_line2 += i_dest_margin;
335     }
336 }
337
338 /*****************************************************************************
339  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
340  *****************************************************************************/
341 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
342                                               picture_t *p_dest )
343 {
344     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
345     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
346     uint8_t *p_u = p_source->U_PIXELS;
347     uint8_t *p_v = p_source->V_PIXELS;
348
349     int i_x, i_y;
350
351     const int i_source_margin = p_source->p->i_pitch
352                                  - p_source->p->i_visible_pitch;
353     const int i_dest_margin = p_dest->p->i_pitch
354                                - p_dest->p->i_visible_pitch;
355
356     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
357     {
358         p_line1 = p_line2;
359         p_line2 += p_dest->p->i_pitch;
360
361         p_y1 = p_y2;
362         p_y2 += p_source->p[Y_PLANE].i_pitch;
363
364         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
365         {
366 #if defined (MODULE_NAME_IS_i420_yuy2)
367             C_YUV420_UYVY( );
368             C_YUV420_UYVY( );
369             C_YUV420_UYVY( );
370             C_YUV420_UYVY( );
371 #else
372             MMX_CALL( MMX_YUV420_UYVY );
373 #endif
374         }
375
376         p_y1 += i_source_margin;
377         p_y2 += i_source_margin;
378         p_line1 += i_dest_margin;
379         p_line2 += i_dest_margin;
380     }
381 }
382
383 /*****************************************************************************
384  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
385  *****************************************************************************/
386 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
387                                               picture_t *p_dest )
388 {
389     /* FIXME: TODO ! */
390     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
391 }
392
393 /*****************************************************************************
394  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
395  *****************************************************************************/
396 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
397                                               picture_t *p_dest )
398 {
399     uint8_t *p_line1 = p_dest->p->p_pixels +
400                        p_dest->p->i_visible_lines * p_dest->p->i_pitch
401                        + p_dest->p->i_pitch;
402     uint8_t *p_line2 = p_dest->p->p_pixels +
403                        p_dest->p->i_visible_lines * p_dest->p->i_pitch;
404     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
405     uint8_t *p_u = p_source->U_PIXELS;
406     uint8_t *p_v = p_source->V_PIXELS;
407
408     int i_x, i_y;
409
410     const int i_source_margin = p_source->p->i_pitch
411                                  - p_source->p->i_visible_pitch;
412     const int i_dest_margin = p_dest->p->i_pitch
413                                - p_dest->p->i_visible_pitch;
414
415     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
416     {
417         p_line1 -= 3 * p_dest->p->i_pitch;
418         p_line2 -= 3 * p_dest->p->i_pitch;
419
420         p_y1 = p_y2;
421         p_y2 += p_source->p[Y_PLANE].i_pitch;
422
423         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
424         {
425 #if defined (MODULE_NAME_IS_i420_yuy2)
426             C_YUV420_UYVY( );
427             C_YUV420_UYVY( );
428             C_YUV420_UYVY( );
429             C_YUV420_UYVY( );
430 #else
431             MMX_CALL( MMX_YUV420_UYVY );
432 #endif
433         }
434
435         p_y1 += i_source_margin;
436         p_y2 += i_source_margin;
437         p_line1 += i_dest_margin;
438         p_line2 += i_dest_margin;
439     }
440 }
441 #endif // !defined (MODULE_NAME_IS_i420_yuy2_altivec)
442
443 /*****************************************************************************
444  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
445  *****************************************************************************/
446 #if defined (MODULE_NAME_IS_i420_yuy2)
447 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
448                                               picture_t *p_dest )
449 {
450     uint8_t *p_line1, *p_line2 = p_dest->p->p_pixels;
451     uint8_t *p_y1, *p_y2 = p_source->Y_PIXELS;
452     uint8_t *p_u = p_source->U_PIXELS;
453     uint8_t *p_v = p_source->V_PIXELS;
454
455     int i_x, i_y;
456
457     const int i_source_margin = p_source->p->i_pitch
458                                  - p_source->p->i_visible_pitch;
459     const int i_dest_margin = p_dest->p->i_pitch
460                                - p_dest->p->i_visible_pitch;
461
462     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
463     {
464         p_line1 = p_line2;
465         p_line2 += p_dest->p->i_pitch;
466
467         p_y1 = p_y2;
468         p_y2 += p_source->p[Y_PLANE].i_pitch;
469
470         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
471         {
472             C_YUV420_Y211( );
473             C_YUV420_Y211( );
474         }
475
476         p_y1 += i_source_margin;
477         p_y2 += i_source_margin;
478         p_line1 += i_dest_margin;
479         p_line2 += i_dest_margin;
480     }
481 }
482 #endif
483