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 *****************************************************************************/
28 #include <string.h> /* strerror() */
33 #include "i422_yuy2.h"
35 #define SRC_FOURCC "I422"
36 #if defined (MODULE_NAME_IS_i422_yuy2)
37 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
39 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
42 /*****************************************************************************
43 * Local and extern prototypes.
44 *****************************************************************************/
45 static int Activate ( vlc_object_t * );
47 static void I422_YUY2 ( vout_thread_t *, picture_t *, picture_t * );
48 static void I422_YVYU ( vout_thread_t *, picture_t *, picture_t * );
49 static void I422_UYVY ( vout_thread_t *, picture_t *, picture_t * );
50 static void I422_IUYV ( vout_thread_t *, picture_t *, picture_t * );
51 static void I422_cyuv ( vout_thread_t *, picture_t *, picture_t * );
52 #if defined (MODULE_NAME_IS_i422_yuy2)
53 static void I422_Y211 ( vout_thread_t *, picture_t *, picture_t * );
54 static void I422_Y211 ( vout_thread_t *, picture_t *, picture_t * );
55 static void I422_YV12 ( vout_thread_t *, picture_t *, picture_t * );
58 /*****************************************************************************
60 *****************************************************************************/
62 #if defined (MODULE_NAME_IS_i422_yuy2)
63 set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
64 set_capability( "chroma", 80 );
65 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
66 set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) );
67 set_capability( "chroma", 100 );
68 add_requirement( MMX );
69 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
70 set_description( _("SSE2 conversions from " SRC_FOURCC " to " DEST_FOURCC) );
71 set_capability( "chroma", 120 );
72 add_requirement( MMX );
74 set_callbacks( Activate, NULL );
77 /*****************************************************************************
78 * Activate: allocate a chroma function
79 *****************************************************************************
80 * This function allocates and initializes a chroma function
81 *****************************************************************************/
82 static int Activate( vlc_object_t *p_this )
84 vout_thread_t *p_vout = (vout_thread_t *)p_this;
86 if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
91 switch( p_vout->render.i_chroma )
93 case VLC_FOURCC('I','4','2','2'):
94 switch( p_vout->output.i_chroma )
96 case VLC_FOURCC('Y','U','Y','2'):
97 case VLC_FOURCC('Y','U','N','V'):
98 p_vout->chroma.pf_convert = I422_YUY2;
101 case VLC_FOURCC('Y','V','Y','U'):
102 p_vout->chroma.pf_convert = I422_YVYU;
105 case VLC_FOURCC('U','Y','V','Y'):
106 case VLC_FOURCC('U','Y','N','V'):
107 case VLC_FOURCC('Y','4','2','2'):
108 p_vout->chroma.pf_convert = I422_UYVY;
111 case VLC_FOURCC('I','U','Y','V'):
112 p_vout->chroma.pf_convert = I422_IUYV;
115 case VLC_FOURCC('c','y','u','v'):
116 p_vout->chroma.pf_convert = I422_cyuv;
119 #if defined (MODULE_NAME_IS_i422_yuy2)
120 case VLC_FOURCC('Y','2','1','1'):
121 p_vout->chroma.pf_convert = I422_Y211;
124 case VLC_FOURCC('Y','V','1','2'):
125 p_vout->chroma.pf_convert = I422_YV12;
140 /* Following functions are local */
142 /*****************************************************************************
143 * I422_YUY2: planar YUV 4:2:2 to packed YUY2 4:2:2
144 *****************************************************************************/
145 static void I422_YUY2( vout_thread_t *p_vout, picture_t *p_source,
148 uint8_t *p_line = p_dest->p->p_pixels;
149 uint8_t *p_y = p_source->Y_PIXELS;
150 uint8_t *p_u = p_source->U_PIXELS;
151 uint8_t *p_v = p_source->V_PIXELS;
155 const int i_source_margin = p_source->p[0].i_pitch
156 - p_source->p[0].i_visible_pitch;
157 const int i_source_margin_c = p_source->p[1].i_pitch
158 - p_source->p[1].i_visible_pitch;
159 const int i_dest_margin = p_dest->p->i_pitch
160 - p_dest->p->i_visible_pitch;
162 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
164 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
165 ((int)p_line|(int)p_y))) )
167 /* use faster SSE2 aligned fetch and store */
168 for( i_y = p_vout->render.i_height ; i_y-- ; )
170 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
172 SSE2_CALL( SSE2_YUV422_YUYV_ALIGNED );
174 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
176 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
178 p_y += i_source_margin;
179 p_u += i_source_margin_c;
180 p_v += i_source_margin_c;
181 p_line += i_dest_margin;
185 /* use slower SSE2 unaligned fetch and store */
186 for( i_y = p_vout->render.i_height ; i_y-- ; )
188 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
190 SSE2_CALL( SSE2_YUV422_YUYV_UNALIGNED );
192 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
194 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
196 p_y += i_source_margin;
197 p_u += i_source_margin_c;
198 p_v += i_source_margin_c;
199 p_line += i_dest_margin;
206 for( i_y = p_vout->render.i_height ; i_y-- ; )
208 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
210 #if defined (MODULE_NAME_IS_i422_yuy2)
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 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
215 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
216 MMX_CALL( MMX_YUV422_YUYV );
219 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
221 C_YUV422_YUYV( p_line, p_y, p_u, p_v );
223 p_y += i_source_margin;
224 p_u += i_source_margin_c;
225 p_v += i_source_margin_c;
226 p_line += i_dest_margin;
228 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
235 /*****************************************************************************
236 * I422_YVYU: planar YUV 4:2:2 to packed YVYU 4:2:2
237 *****************************************************************************/
238 static void I422_YVYU( vout_thread_t *p_vout, picture_t *p_source,
241 uint8_t *p_line = p_dest->p->p_pixels;
242 uint8_t *p_y = p_source->Y_PIXELS;
243 uint8_t *p_u = p_source->U_PIXELS;
244 uint8_t *p_v = p_source->V_PIXELS;
248 const int i_source_margin = p_source->p[0].i_pitch
249 - p_source->p[0].i_visible_pitch;
250 const int i_source_margin_c = p_source->p[1].i_pitch
251 - p_source->p[1].i_visible_pitch;
252 const int i_dest_margin = p_dest->p->i_pitch
253 - p_dest->p->i_visible_pitch;
255 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
257 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
258 ((int)p_line|(int)p_y))) )
260 /* use faster SSE2 aligned fetch and store */
261 for( i_y = p_vout->render.i_height ; i_y-- ; )
263 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
265 SSE2_CALL( SSE2_YUV422_YVYU_ALIGNED );
267 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
269 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
271 p_y += i_source_margin;
272 p_u += i_source_margin_c;
273 p_v += i_source_margin_c;
274 p_line += i_dest_margin;
278 /* use slower SSE2 unaligned fetch and store */
279 for( i_y = p_vout->render.i_height ; i_y-- ; )
281 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
283 SSE2_CALL( SSE2_YUV422_YVYU_UNALIGNED );
285 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
287 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
289 p_y += i_source_margin;
290 p_u += i_source_margin_c;
291 p_v += i_source_margin_c;
292 p_line += i_dest_margin;
299 for( i_y = p_vout->render.i_height ; i_y-- ; )
301 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
303 #if defined (MODULE_NAME_IS_i422_yuy2)
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 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
308 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
309 MMX_CALL( MMX_YUV422_YVYU );
312 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
314 C_YUV422_YVYU( p_line, p_y, p_u, p_v );
316 p_y += i_source_margin;
317 p_u += i_source_margin_c;
318 p_v += i_source_margin_c;
319 p_line += i_dest_margin;
321 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
328 /*****************************************************************************
329 * I422_UYVY: planar YUV 4:2:2 to packed UYVY 4:2:2
330 *****************************************************************************/
331 static void I422_UYVY( vout_thread_t *p_vout, picture_t *p_source,
334 uint8_t *p_line = p_dest->p->p_pixels;
335 uint8_t *p_y = p_source->Y_PIXELS;
336 uint8_t *p_u = p_source->U_PIXELS;
337 uint8_t *p_v = p_source->V_PIXELS;
341 const int i_source_margin = p_source->p[0].i_pitch
342 - p_source->p[0].i_visible_pitch;
343 const int i_source_margin_c = p_source->p[1].i_pitch
344 - p_source->p[1].i_visible_pitch;
345 const int i_dest_margin = p_dest->p->i_pitch
346 - p_dest->p->i_visible_pitch;
348 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
350 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
351 ((int)p_line|(int)p_y))) )
353 /* use faster SSE2 aligned fetch and store */
354 for( i_y = p_vout->render.i_height ; i_y-- ; )
356 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
358 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
360 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
362 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
364 p_y += i_source_margin;
365 p_u += i_source_margin_c;
366 p_v += i_source_margin_c;
367 p_line += i_dest_margin;
371 /* use slower SSE2 unaligned fetch and store */
372 for( i_y = p_vout->render.i_height ; i_y-- ; )
374 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
376 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
378 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
380 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
382 p_y += i_source_margin;
383 p_u += i_source_margin_c;
384 p_v += i_source_margin_c;
385 p_line += i_dest_margin;
392 for( i_y = p_vout->render.i_height ; i_y-- ; )
394 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
396 #if defined (MODULE_NAME_IS_i422_yuy2)
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 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
401 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
402 MMX_CALL( MMX_YUV422_UYVY );
405 for( i_x = ( p_vout->render.i_width % 8 ) / 2; i_x-- ; )
407 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
409 p_y += i_source_margin;
410 p_u += i_source_margin_c;
411 p_v += i_source_margin_c;
412 p_line += i_dest_margin;
414 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
421 /*****************************************************************************
422 * I422_IUYV: planar YUV 4:2:2 to interleaved packed IUYV 4:2:2
423 *****************************************************************************/
424 static void I422_IUYV( vout_thread_t *p_vout, picture_t *p_source,
428 msg_Err( p_vout, "I422_IUYV unimplemented, please harass <sam@zoy.org>" );
431 /*****************************************************************************
432 * I422_cyuv: planar YUV 4:2:2 to upside-down packed UYVY 4:2:2
433 *****************************************************************************/
434 static void I422_cyuv( vout_thread_t *p_vout, picture_t *p_source,
437 uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
438 uint8_t *p_y = p_source->Y_PIXELS;
439 uint8_t *p_u = p_source->U_PIXELS;
440 uint8_t *p_v = p_source->V_PIXELS;
444 const int i_source_margin = p_source->p[0].i_pitch
445 - p_source->p[0].i_visible_pitch;
446 const int i_source_margin_c = p_source->p[1].i_pitch
447 - p_source->p[1].i_visible_pitch;
448 const int i_dest_margin = p_dest->p->i_pitch
449 - p_dest->p->i_visible_pitch;
451 #if defined (MODULE_NAME_IS_i422_yuy2_sse2)
453 if( 0 == (15 & (p_source->p[Y_PLANE].i_pitch|p_dest->p->i_pitch|
454 ((int)p_line|(int)p_y))) )
456 /* use faster SSE2 aligned fetch and store */
457 for( i_y = p_vout->render.i_height ; i_y-- ; )
459 p_line -= 2 * p_dest->p->i_pitch;
461 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
463 SSE2_CALL( SSE2_YUV422_UYVY_ALIGNED );
465 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
467 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
469 p_y += i_source_margin;
470 p_u += i_source_margin_c;
471 p_v += i_source_margin_c;
472 p_line += i_dest_margin;
476 /* use slower SSE2 unaligned fetch and store */
477 for( i_y = p_vout->render.i_height ; i_y-- ; )
479 p_line -= 2 * p_dest->p->i_pitch;
481 for( i_x = p_vout->render.i_width / 16 ; i_x-- ; )
483 SSE2_CALL( SSE2_YUV422_UYVY_UNALIGNED );
485 for( i_x = ( p_vout->render.i_width % 16 ) / 2; i_x-- ; )
487 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
489 p_y += i_source_margin;
490 p_u += i_source_margin_c;
491 p_v += i_source_margin_c;
492 p_line += i_dest_margin;
499 for( i_y = p_vout->render.i_height ; i_y-- ; )
501 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
503 p_line -= 2 * p_dest->p->i_pitch;
505 #if defined (MODULE_NAME_IS_i422_yuy2)
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 C_YUV422_UYVY( p_line, p_y, p_u, p_v );
510 #elif defined (MODULE_NAME_IS_i422_yuy2_mmx)
511 MMX_CALL( MMX_YUV422_UYVY );
514 p_y += i_source_margin;
515 p_u += i_source_margin_c;
516 p_v += i_source_margin_c;
517 p_line += i_dest_margin;
519 #if defined (MODULE_NAME_IS_i422_yuy2_mmx)
521 #elif defined (MODULE_NAME_IS_i422_yuy2_sse2)
528 /*****************************************************************************
529 * I422_Y211: planar YUV 4:2:2 to packed YUYV 2:1:1
530 *****************************************************************************/
531 #if defined (MODULE_NAME_IS_i422_yuy2)
532 static void I422_Y211( vout_thread_t *p_vout, picture_t *p_source,
535 uint8_t *p_line = p_dest->p->p_pixels + p_dest->p->i_visible_lines * p_dest->p->i_pitch;
536 uint8_t *p_y = p_source->Y_PIXELS;
537 uint8_t *p_u = p_source->U_PIXELS;
538 uint8_t *p_v = p_source->V_PIXELS;
542 for( i_y = p_vout->render.i_height ; i_y-- ; )
544 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
546 C_YUV422_Y211( p_line, p_y, p_u, p_v );
547 C_YUV422_Y211( p_line, p_y, p_u, p_v );
554 /*****************************************************************************
555 * I422_YV12: planar YUV 4:2:2 to planar YV12
556 *****************************************************************************/
557 #if defined (MODULE_NAME_IS_i422_yuy2)
558 static void I422_YV12( vout_thread_t *p_vout, picture_t *p_source,
561 uint16_t i_dpy = p_dest->p[Y_PLANE].i_pitch;
562 uint16_t i_spy = p_source->p[Y_PLANE].i_pitch;
563 uint16_t i_dpuv = p_dest->p[U_PLANE].i_pitch;
564 uint16_t i_spuv = p_source->p[U_PLANE].i_pitch;
565 uint16_t i_width = p_vout->render.i_width;
566 uint16_t i_y = p_vout->render.i_height;
567 uint8_t *p_dy = p_dest->Y_PIXELS + (i_y-1)*i_dpy;
568 uint8_t *p_y = p_source->Y_PIXELS + (i_y-1)*i_spy;
569 uint8_t *p_du = p_dest->U_PIXELS + (i_y/2-1)*i_dpuv;
570 uint8_t *p_u = p_source->U_PIXELS + (i_y-1)*i_spuv;
571 uint8_t *p_dv = p_dest->V_PIXELS + (i_y/2-1)*i_dpuv;
572 uint8_t *p_v = p_source->V_PIXELS + (i_y-1)*i_spuv;
577 memcpy(p_dy, p_y, i_width); p_dy -= i_dpy; p_y -= i_spy;
578 memcpy(p_dy, p_y, i_width); p_dy -= i_dpy; p_y -= i_spy;
579 memcpy(p_du, p_u, i_width/2); p_du -= i_dpuv; p_u -= 2*i_spuv;
580 memcpy(p_dv, p_v, i_width/2); p_dv -= i_dpuv; p_v -= 2*i_spuv;