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.9 2002/06/01 16:45:34 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
28 #include <string.h> /* strerror() */
29 #include <stdlib.h> /* malloc(), free() */
34 #include "i420_yuy2.h"
36 #define SRC_FOURCC "I420,IYUV,YV12"
38 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
39 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
41 # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
44 /*****************************************************************************
45 * Local and extern prototypes.
46 *****************************************************************************/
47 static void chroma_getfunctions ( function_list_t * p_function_list );
49 static int chroma_Init ( vout_thread_t *p_vout );
50 static void chroma_End ( vout_thread_t *p_vout );
52 static void I420_YUY2 ( vout_thread_t *, picture_t *, picture_t * );
53 static void I420_YVYU ( vout_thread_t *, picture_t *, picture_t * );
54 static void I420_UYVY ( vout_thread_t *, picture_t *, picture_t * );
55 static void I420_IUYV ( vout_thread_t *, picture_t *, picture_t * );
56 static void I420_cyuv ( vout_thread_t *, picture_t *, picture_t * );
57 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
58 static void I420_Y211 ( vout_thread_t *, picture_t *, picture_t * );
61 #ifdef MODULE_NAME_IS_chroma_i420_yuy2_mmx
62 static unsigned long long i_00ffw;
63 static unsigned long long i_80w;
66 /*****************************************************************************
67 * Build configuration tree.
68 *****************************************************************************/
73 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
74 SET_DESCRIPTION( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) )
75 ADD_CAPABILITY( CHROMA, 80 )
76 #elif defined (MODULE_NAME_IS_chroma_i420_yuy2_mmx)
77 SET_DESCRIPTION( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) )
78 ADD_CAPABILITY( CHROMA, 100 )
79 ADD_REQUIREMENT( MMX )
80 /* Initialize MMX-specific constants */
81 i_00ffw = 0x00ff00ff00ff00ff;
82 i_80w = 0x0000000080808080;
87 chroma_getfunctions( &p_module->p_functions->chroma );
90 MODULE_DEACTIVATE_START
91 MODULE_DEACTIVATE_STOP
93 /*****************************************************************************
94 * Functions exported as capabilities. They are declared as static so that
95 * we don't pollute the namespace too much.
96 *****************************************************************************/
97 static void chroma_getfunctions( function_list_t * p_function_list )
99 p_function_list->functions.chroma.pf_init = chroma_Init;
100 p_function_list->functions.chroma.pf_end = chroma_End;
103 /*****************************************************************************
104 * chroma_Init: allocate a chroma function
105 *****************************************************************************
106 * This function allocates and initializes a chroma function
107 *****************************************************************************/
108 static int chroma_Init( vout_thread_t *p_vout )
110 if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
115 switch( p_vout->render.i_chroma )
120 switch( p_vout->output.i_chroma )
124 p_vout->chroma.pf_convert = I420_YUY2;
128 p_vout->chroma.pf_convert = I420_YVYU;
134 p_vout->chroma.pf_convert = I420_UYVY;
138 p_vout->chroma.pf_convert = I420_IUYV;
142 p_vout->chroma.pf_convert = I420_cyuv;
145 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
147 p_vout->chroma.pf_convert = I420_Y211;
163 /*****************************************************************************
164 * chroma_End: free the chroma function
165 *****************************************************************************
166 * This function frees the previously allocated chroma function
167 *****************************************************************************/
168 static void chroma_End( vout_thread_t *p_vout )
173 /* Following functions are local */
175 /*****************************************************************************
176 * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
177 *****************************************************************************/
178 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
181 u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
182 u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
183 u8 *p_u = p_source->U_PIXELS;
184 u8 *p_v = p_source->V_PIXELS;
188 const int i_source_margin = p_source->p->b_margin ?
189 p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
190 const int i_dest_margin = p_dest->p->b_margin ?
191 p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
193 for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
196 p_line2 += p_dest->p->i_pitch;
199 p_y2 += p_source->p[Y_PLANE].i_pitch;
201 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
203 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
209 MMX_CALL( MMX_YUV420_YUYV );
213 p_y1 += i_source_margin;
214 p_y2 += i_source_margin;
215 p_line1 += i_dest_margin;
216 p_line2 += i_dest_margin;
220 /*****************************************************************************
221 * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
222 *****************************************************************************/
223 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
226 u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
227 u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
228 u8 *p_u = p_source->U_PIXELS;
229 u8 *p_v = p_source->V_PIXELS;
233 const int i_source_margin = p_source->p->b_margin ?
234 p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
235 const int i_dest_margin = p_dest->p->b_margin ?
236 p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
238 for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
241 p_line2 += p_dest->p->i_pitch;
244 p_y2 += p_source->p[Y_PLANE].i_pitch;
246 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
248 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
254 MMX_CALL( MMX_YUV420_YVYU );
258 p_y1 += i_source_margin;
259 p_y2 += i_source_margin;
260 p_line1 += i_dest_margin;
261 p_line2 += i_dest_margin;
265 /*****************************************************************************
266 * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
267 *****************************************************************************/
268 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
271 u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
272 u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
273 u8 *p_u = p_source->U_PIXELS;
274 u8 *p_v = p_source->V_PIXELS;
278 const int i_source_margin = p_source->p->b_margin ?
279 p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
280 const int i_dest_margin = p_dest->p->b_margin ?
281 p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
283 for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
286 p_line2 += p_dest->p->i_pitch;
289 p_y2 += p_source->p[Y_PLANE].i_pitch;
291 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
293 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
299 MMX_CALL( MMX_YUV420_UYVY );
303 p_y1 += i_source_margin;
304 p_y2 += i_source_margin;
305 p_line1 += i_dest_margin;
306 p_line2 += i_dest_margin;
310 /*****************************************************************************
311 * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
312 *****************************************************************************/
313 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
317 msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
320 /*****************************************************************************
321 * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
322 *****************************************************************************/
323 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
326 u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch
327 + p_dest->p->i_pitch;
328 u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch;
329 u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
330 u8 *p_u = p_source->U_PIXELS;
331 u8 *p_v = p_source->V_PIXELS;
335 const int i_source_margin = p_source->p->b_margin ?
336 p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
337 const int i_dest_margin = p_dest->p->b_margin ?
338 p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
340 for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
342 p_line1 -= 3 * p_dest->p->i_pitch;
343 p_line2 -= 3 * p_dest->p->i_pitch;
346 p_y2 += p_source->p[Y_PLANE].i_pitch;
348 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
350 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
356 MMX_CALL( MMX_YUV420_UYVY );
360 p_y1 += i_source_margin;
361 p_y2 += i_source_margin;
362 p_line1 += i_dest_margin;
363 p_line2 += i_dest_margin;
367 /*****************************************************************************
368 * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
369 *****************************************************************************/
370 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
371 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
374 u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
375 u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
376 u8 *p_u = p_source->U_PIXELS;
377 u8 *p_v = p_source->V_PIXELS;
381 const int i_source_margin = p_source->p->b_margin ?
382 p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
383 const int i_dest_margin = p_dest->p->b_margin ?
384 p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
386 for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
389 p_line2 += p_dest->p->i_pitch;
392 p_y2 += p_source->p[Y_PLANE].i_pitch;
394 for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
400 p_y1 += i_source_margin;
401 p_y2 += i_source_margin;
402 p_line1 += i_dest_margin;
403 p_line2 += i_dest_margin;