1 /*****************************************************************************
2 * i422_yuy2.c : YUV to YUV conversion module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Damien Fouilleul <damienf@videolan.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include "i422_yuy2.h"
34 #define SRC_FOURCC "I422"
35 #if defined (MODULE_NAME_IS_i422_yuy2)
36 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
38 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
41 /*****************************************************************************
42 * Local and extern prototypes.
43 *****************************************************************************/
44 static int Activate ( vlc_object_t * );
46 static void I422_YUY2 ( vout_thread_t *, picture_t *, picture_t * );
47 static void I422_YVYU ( vout_thread_t *, picture_t *, picture_t * );
48 static void I422_UYVY ( vout_thread_t *, picture_t *, picture_t * );
49 static void I422_IUYV ( vout_thread_t *, picture_t *, picture_t * );
50 static void I422_cyuv ( vout_thread_t *, picture_t *, picture_t * );
51 #if defined (MODULE_NAME_IS_i422_yuy2)
52 static void I422_Y211 ( vout_thread_t *, picture_t *, picture_t * );
53 static void I422_Y211 ( vout_thread_t *, picture_t *, picture_t * );
54 static void I422_YV12 ( vout_thread_t *, picture_t *, picture_t * );
57 /*****************************************************************************
59 *****************************************************************************/
61 #if defined (MODULE_NAME_IS_i422_yuy2)
62 set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
63 set_capability( "chroma", 80 );
64 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
65 set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
66 set_capability( "chroma", 100 );
67 add_requirement( MMX );
68 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
69 set_description( _("SSE2 conversions from " SRC_FOURCC " to " DEST_FOURCC) );
70 set_capability( "chroma", 120 );
71 add_requirement( MMX );
73 set_callbacks( Activate, NULL );
76 /*****************************************************************************
77 * Activate: allocate a chroma function
78 *****************************************************************************
79 * This function allocates and initializes a chroma function
80 *****************************************************************************/
81 static int Activate( vlc_object_t *p_this )
83 vout_thread_t *p_vout = (vout_thread_t *)p_this;
85 if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
90 switch( p_vout->render.i_chroma )
92 case VLC_FOURCC('I','4','2','2'):
93 switch( p_vout->output.i_chroma )
95 case VLC_FOURCC('Y','U','Y','2'):
96 case VLC_FOURCC('Y','U','N','V'):
97 p_vout->chroma.pf_convert = I422_YUY2;
100 case VLC_FOURCC('Y','V','Y','U'):
101 p_vout->chroma.pf_convert = I422_YVYU;
104 case VLC_FOURCC('U','Y','V','Y'):
105 case VLC_FOURCC('U','Y','N','V'):
106 case VLC_FOURCC('Y','4','2','2'):
107 p_vout->chroma.pf_convert = I422_UYVY;
110 case VLC_FOURCC('I','U','Y','V'):
111 p_vout->chroma.pf_convert = I422_IUYV;
114 case VLC_FOURCC('c','y','u','v'):
115 p_vout->chroma.pf_convert = I422_cyuv;
118 #if defined (MODULE_NAME_IS_i422_yuy2)
119 case VLC_FOURCC('Y','2','1','1'):
120 p_vout->chroma.pf_convert = I422_Y211;
123 case VLC_FOURCC('Y','V','1','2'):
124 p_vout->chroma.pf_convert = I422_YV12;
139 /* Following functions are local */
141 /*****************************************************************************
142 * I422_YUY2: planar YUV 4:2:2 to packed YUY2 4:2:2
143 *****************************************************************************/
144 static void I422_YUY2( vout_thread_t *p_vout, picture_t *p_source,
147 uint8_t *p_line = p_dest->p->p_pixels;
148 uint8_t *p_y = p_source->Y_PIXELS;
149 uint8_t *p_u = p_source->U_PIXELS;
150 uint8_t *p_v = p_source->V_PIXELS;
154 const int i_source_margin = p_source->p[0].i_pitch
155 - p_source->p[0].i_visible_pitch;
156 const int i_source_margin_c = p_source->p[1].i_pitch
157 - p_source->p[1].i_visible_pitch;
158 const int i_dest_margin = p_dest->p->i_pitch
159 - p_dest->p->i_visible_pitch;
161 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
163 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
164 ((int)p_line|(int)p_y))) )
166 /* use faster SSE2 aligned fetch and store */
167 for( i_y = p_vout->render.i_height ; i_y-- ; )
169 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
171 SSE2_CALL( SSE2_YUV422_YUYV_ALIGNED );
173 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
175 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
177 p_y += i_source_margin;
178 p_u += i_source_margin_c;
179 p_v += i_source_margin_c;
180 p_line += i_dest_margin;
184 /* use slower SSE2 unaligned fetch and store */
185 for( i_y = p_vout->render.i_height ; i_y-- ; )
187 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
189 SSE2_CALL( SSE2_YUV422_YUYV_UNALIGNED );
191 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
193 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
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;
205 for( i_y = p_vout->render.i_height ; i_y-- ; )
207 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
209 #if defined (MODULE_NAME_IS_i422_yuy2)
210 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
211 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
212 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
213 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
214 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
215 MMX_CALL( MMX_YUV422_YUYV );
218 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
220 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
222 p_y += i_source_margin;
223 p_u += i_source_margin_c;
224 p_v += i_source_margin_c;
225 p_line += i_dest_margin;
227 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
234 /*****************************************************************************
235 * I422_YVYU: planar YUV 4:2:2 to packed YVYU 4:2:2
236 *****************************************************************************/
237 static void I422_YVYU( vout_thread_t *p_vout, picture_t *p_source,
240 uint8_t *p_line = p_dest->p->p_pixels;
241 uint8_t *p_y = p_source->Y_PIXELS;
242 uint8_t *p_u = p_source->U_PIXELS;
243 uint8_t *p_v = p_source->V_PIXELS;
247 const int i_source_margin = p_source->p[0].i_pitch
248 - p_source->p[0].i_visible_pitch;
249 const int i_source_margin_c = p_source->p[1].i_pitch
250 - p_source->p[1].i_visible_pitch;
251 const int i_dest_margin = p_dest->p->i_pitch
252 - p_dest->p->i_visible_pitch;
254 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
256 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
257 ((int)p_line|(int)p_y))) )
259 /* use faster SSE2 aligned fetch and store */
260 for( i_y = p_vout->render.i_height ; i_y-- ; )
262 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
264 SSE2_CALL( SSE2_YUV422_YVYU_ALIGNED );
266 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
268 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
270 p_y += i_source_margin;
271 p_u += i_source_margin_c;
272 p_v += i_source_margin_c;
273 p_line += i_dest_margin;
277 /* use slower SSE2 unaligned fetch and store */
278 for( i_y = p_vout->render.i_height ; i_y-- ; )
280 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
282 SSE2_CALL( SSE2_YUV422_YVYU_UNALIGNED );
284 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
286 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
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;
298 for( i_y = p_vout->render.i_height ; i_y-- ; )
300 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
302 #if defined (MODULE_NAME_IS_i422_yuy2)
303 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
304 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
305 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
306 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
307 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
308 MMX_CALL( MMX_YUV422_YVYU );
311 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
313 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
315 p_y += i_source_margin;
316 p_u += i_source_margin_c;
317 p_v += i_source_margin_c;
318 p_line += i_dest_margin;
320 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
327 /*****************************************************************************
328 * I422_UYVY: planar YUV 4:2:2 to packed UYVY 4:2:2
329 *****************************************************************************/
330 static void I422_UYVY( vout_thread_t *p_vout, picture_t *p_source,
333 uint8_t *p_line = p_dest->p->p_pixels;
334 uint8_t *p_y = p_source->Y_PIXELS;
335 uint8_t *p_u = p_source->U_PIXELS;
336 uint8_t *p_v = p_source->V_PIXELS;
340 const int i_source_margin = p_source->p[0].i_pitch
341 - p_source->p[0].i_visible_pitch;
342 const int i_source_margin_c = p_source->p[1].i_pitch
343 - p_source->p[1].i_visible_pitch;
344 const int i_dest_margin = p_dest->p->i_pitch
345 - p_dest->p->i_visible_pitch;
347 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
349 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
350 ((int)p_line|(int)p_y))) )
352 /* use faster SSE2 aligned fetch and store */
353 for( i_y = p_vout->render.i_height ; i_y-- ; )
355 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
357 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
359 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
361 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
363 p_y += i_source_margin;
364 p_u += i_source_margin_c;
365 p_v += i_source_margin_c;
366 p_line += i_dest_margin;
370 /* use slower SSE2 unaligned fetch and store */
371 for( i_y = p_vout->render.i_height ; i_y-- ; )
373 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
375 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
377 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
379 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
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;
391 for( i_y = p_vout->render.i_height ; i_y-- ; )
393 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
395 #if defined (MODULE_NAME_IS_i422_yuy2)
396 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
397 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
398 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
399 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
400 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
401 MMX_CALL( MMX_YUV422_UYVY );
404 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
406 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
408 p_y += i_source_margin;
409 p_u += i_source_margin_c;
410 p_v += i_source_margin_c;
411 p_line += i_dest_margin;
413 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
420 /*****************************************************************************
421 * I422_IUYV: planar YUV 4:2:2 to interleaved packed IUYV 4:2:2
422 *****************************************************************************/
423 static void I422_IUYV( vout_thread_t *p_vout, picture_t *p_source,
427 msg_Err( p_vout, "I422_IUYV unimplemented, please harass <sam@zoy.org>" );
430 /*****************************************************************************
431 * I422_cyuv: planar YUV 4:2:2 to upside-down packed UYVY 4:2:2
432 *****************************************************************************/
433 static void I422_cyuv( vout_thread_t *p_vout, picture_t *p_source,
436 uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
437 uint8_t *p_y = p_source->Y_PIXELS;
438 uint8_t *p_u = p_source->U_PIXELS;
439 uint8_t *p_v = p_source->V_PIXELS;
443 const int i_source_margin = p_source->p[0].i_pitch
444 - p_source->p[0].i_visible_pitch;
445 const int i_source_margin_c = p_source->p[1].i_pitch
446 - p_source->p[1].i_visible_pitch;
447 const int i_dest_margin = p_dest->p->i_pitch
448 - p_dest->p->i_visible_pitch;
450 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
452 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
453 ((int)p_line|(int)p_y))) )
455 /* use faster SSE2 aligned fetch and store */
456 for( i_y = p_vout->render.i_height ; i_y-- ; )
458 p_line -= 2 * p_dest->p->i_pitch;
460 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
462 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
464 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
466 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
468 p_y += i_source_margin;
469 p_u += i_source_margin_c;
470 p_v += i_source_margin_c;
471 p_line += i_dest_margin;
475 /* use slower SSE2 unaligned fetch and store */
476 for( i_y = p_vout->render.i_height ; i_y-- ; )
478 p_line -= 2 * p_dest->p->i_pitch;
480 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
482 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
484 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
486 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
488 p_y += i_source_margin;
489 p_u += i_source_margin_c;
490 p_v += i_source_margin_c;
491 p_line += i_dest_margin;
498 for( i_y = p_vout->render.i_height ; i_y-- ; )
500 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
502 p_line -= 2 * p_dest->p->i_pitch;
504 #if defined (MODULE_NAME_IS_i422_yuy2)
505 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
506 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
507 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
508 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
509 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
510 MMX_CALL( MMX_YUV422_UYVY );
513 p_y += i_source_margin;
514 p_u += i_source_margin_c;
515 p_v += i_source_margin_c;
516 p_line += i_dest_margin;
518 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
520 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
527 /*****************************************************************************
528 * I422_Y211: planar YUV 4:2:2 to packed YUYV 2:1:1
529 *****************************************************************************/
530 #if defined (MODULE_NAME_IS_i422_yuy2)
531 static void I422_Y211( vout_thread_t *p_vout, picture_t *p_source,
534 uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
535 uint8_t *p_y = p_source->Y_PIXELS;
536 uint8_t *p_u = p_source->U_PIXELS;
537 uint8_t *p_v = p_source->V_PIXELS;
541 for( i_y = p_vout->render.i_height ; i_y-- ; )
543 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
545 C_YUV422_Y211( p_line, p_y, p_u, p_v );
546 C_YUV422_Y211( p_line, p_y, p_u, p_v );
553 /*****************************************************************************
554 * I422_YV12: planar YUV 4:2:2 to planar YV12
555 *****************************************************************************/
556 #if defined (MODULE_NAME_IS_i422_yuy2)
557 static void I422_YV12( vout_thread_t *p_vout, picture_t *p_source,
560 uint16_t i_dpy = p_dest->p[Y_PLANE].i_pitch;
561 uint16_t i_spy = p_source->p[Y_PLANE].i_pitch;
562 uint16_t i_dpuv = p_dest->p[U_PLANE].i_pitch;
563 uint16_t i_spuv = p_source->p[U_PLANE].i_pitch;
564 uint16_t i_width = p_vout->render.i_width;
565 uint16_t i_y = p_vout->render.i_height;
566 uint8_t *p_dy = p_dest->Y_PIXELS + (i_y-1)*i_dpy;
567 uint8_t *p_y = p_source->Y_PIXELS + (i_y-1)*i_spy;
568 uint8_t *p_du = p_dest->U_PIXELS + (i_y/2-1)*i_dpuv;
569 uint8_t *p_u = p_source->U_PIXELS + (i_y-1)*i_spuv;
570 uint8_t *p_dv = p_dest->V_PIXELS + (i_y/2-1)*i_dpuv;
571 uint8_t *p_v = p_source->V_PIXELS + (i_y-1)*i_spuv;
576 memcpy(p_dy, p_y, i_width); p_dy -= i_dpy; p_y -= i_spy;
577 memcpy(p_dy, p_y, i_width); p_dy -= i_dpy; p_y -= i_spy;
578 memcpy(p_du, p_u, i_width/2); p_du -= i_dpuv; p_u -= 2*i_spuv;
579 memcpy(p_dv, p_v, i_width/2); p_dv -= i_dpuv; p_v -= 2*i_spuv;