]> git.sesse.net Git - vlc/blob - plugins/chroma/i420_yuy2.c
* ALL: the first libvlc commit.
[vlc] / plugins / 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.8 2002/06/01 12:31:58 sam 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 <errno.h>                                                 /* ENOMEM */
28 #include <string.h>                                            /* strerror() */
29 #include <stdlib.h>                                      /* malloc(), free() */
30
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33
34 #include "i420_yuy2.h"
35
36 #define SRC_FOURCC  "I420,IYUV,YV12"
37
38 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
39 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211"
40 #else
41 #    define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv"
42 #endif
43
44 /*****************************************************************************
45  * Local and extern prototypes.
46  *****************************************************************************/
47 static void chroma_getfunctions ( function_list_t * p_function_list );
48
49 static int  chroma_Init         ( vout_thread_t *p_vout );
50 static void chroma_End          ( vout_thread_t *p_vout );
51
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 * );
59 #endif
60
61 /*****************************************************************************
62  * Build configuration tree.
63  *****************************************************************************/
64 MODULE_CONFIG_START
65 MODULE_CONFIG_STOP
66
67 MODULE_INIT_START
68 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
69     SET_DESCRIPTION( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) )
70     ADD_CAPABILITY( CHROMA, 80 )
71 #elif defined (MODULE_NAME_IS_chroma_i420_yuy2_mmx)
72     SET_DESCRIPTION( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) )
73     ADD_CAPABILITY( CHROMA, 100 )
74     ADD_REQUIREMENT( MMX )
75 #endif
76 MODULE_INIT_STOP
77
78 MODULE_ACTIVATE_START
79     chroma_getfunctions( &p_module->p_functions->chroma );
80 MODULE_ACTIVATE_STOP
81
82 MODULE_DEACTIVATE_START
83 MODULE_DEACTIVATE_STOP
84
85 /*****************************************************************************
86  * Functions exported as capabilities. They are declared as static so that
87  * we don't pollute the namespace too much.
88  *****************************************************************************/
89 static void chroma_getfunctions( function_list_t * p_function_list )
90 {
91     p_function_list->functions.chroma.pf_init = chroma_Init;
92     p_function_list->functions.chroma.pf_end  = chroma_End;
93 }
94
95 /*****************************************************************************
96  * chroma_Init: allocate a chroma function
97  *****************************************************************************
98  * This function allocates and initializes a chroma function
99  *****************************************************************************/
100 static int chroma_Init( vout_thread_t *p_vout )
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 FOURCC_YV12:
110         case FOURCC_I420:
111         case FOURCC_IYUV:
112             switch( p_vout->output.i_chroma )
113             {
114                 case FOURCC_YUY2:
115                 case FOURCC_YUNV:
116                     p_vout->chroma.pf_convert = I420_YUY2;
117                     break;
118
119                 case FOURCC_YVYU:
120                     p_vout->chroma.pf_convert = I420_YVYU;
121                     break;
122
123                 case FOURCC_UYVY:
124                 case FOURCC_UYNV:
125                 case FOURCC_Y422:
126                     p_vout->chroma.pf_convert = I420_UYVY;
127                     break;
128
129                 case FOURCC_IUYV:
130                     p_vout->chroma.pf_convert = I420_IUYV;
131                     break;
132
133                 case FOURCC_cyuv:
134                     p_vout->chroma.pf_convert = I420_cyuv;
135                     break;
136
137 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
138                 case FOURCC_Y211:
139                     p_vout->chroma.pf_convert = I420_Y211;
140                     break;
141 #endif
142
143                 default:
144                     return -1;
145             }
146             break;
147
148         default:
149             return -1;
150     }
151
152     return 0;
153 }
154
155 /*****************************************************************************
156  * chroma_End: free the chroma function
157  *****************************************************************************
158  * This function frees the previously allocated chroma function
159  *****************************************************************************/
160 static void chroma_End( vout_thread_t *p_vout )
161 {
162     ;
163 }
164
165 /* Following functions are local */
166
167 /*****************************************************************************
168  * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2
169  *****************************************************************************/
170 static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source,
171                                               picture_t *p_dest )
172 {
173     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
174     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
175     u8 *p_u = p_source->U_PIXELS;
176     u8 *p_v = p_source->V_PIXELS;
177
178     int i_x, i_y;
179
180     const int i_source_margin = p_source->p->b_margin ?
181         p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
182     const int i_dest_margin = p_dest->p->b_margin ?
183         p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
184
185     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
186     {
187         p_line1 = p_line2;
188         p_line2 += p_dest->p->i_pitch;
189
190         p_y1 = p_y2;
191         p_y2 += p_source->p[Y_PLANE].i_pitch;
192
193         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
194         {
195 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
196             C_YUV420_YUYV( );
197             C_YUV420_YUYV( );
198             C_YUV420_YUYV( );
199             C_YUV420_YUYV( );
200 #else
201             MMX_CALL( MMX_YUV420_YUYV );
202 #endif
203         }
204
205         p_y1 += i_source_margin;
206         p_y2 += i_source_margin;
207         p_line1 += i_dest_margin;
208         p_line2 += i_dest_margin;
209     }
210 }
211
212 /*****************************************************************************
213  * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2
214  *****************************************************************************/
215 static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source,
216                                               picture_t *p_dest )
217 {
218     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
219     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
220     u8 *p_u = p_source->U_PIXELS;
221     u8 *p_v = p_source->V_PIXELS;
222
223     int i_x, i_y;
224
225     const int i_source_margin = p_source->p->b_margin ?
226         p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
227     const int i_dest_margin = p_dest->p->b_margin ?
228         p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
229
230     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
231     {
232         p_line1 = p_line2;
233         p_line2 += p_dest->p->i_pitch;
234
235         p_y1 = p_y2;
236         p_y2 += p_source->p[Y_PLANE].i_pitch;
237
238         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
239         {
240 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
241             C_YUV420_YVYU( );
242             C_YUV420_YVYU( );
243             C_YUV420_YVYU( );
244             C_YUV420_YVYU( );
245 #else
246             MMX_CALL( MMX_YUV420_YVYU );
247 #endif
248         }
249
250         p_y1 += i_source_margin;
251         p_y2 += i_source_margin;
252         p_line1 += i_dest_margin;
253         p_line2 += i_dest_margin;
254     }
255 }
256
257 /*****************************************************************************
258  * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2
259  *****************************************************************************/
260 static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source,
261                                               picture_t *p_dest )
262 {
263     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
264     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
265     u8 *p_u = p_source->U_PIXELS;
266     u8 *p_v = p_source->V_PIXELS;
267
268     int i_x, i_y;
269
270     const int i_source_margin = p_source->p->b_margin ?
271         p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
272     const int i_dest_margin = p_dest->p->b_margin ?
273         p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
274
275     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
276     {
277         p_line1 = p_line2;
278         p_line2 += p_dest->p->i_pitch;
279
280         p_y1 = p_y2;
281         p_y2 += p_source->p[Y_PLANE].i_pitch;
282
283         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
284         {
285 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
286             C_YUV420_UYVY( );
287             C_YUV420_UYVY( );
288             C_YUV420_UYVY( );
289             C_YUV420_UYVY( );
290 #else
291             MMX_CALL( MMX_YUV420_UYVY );
292 #endif
293         }
294
295         p_y1 += i_source_margin;
296         p_y2 += i_source_margin;
297         p_line1 += i_dest_margin;
298         p_line2 += i_dest_margin;
299     }
300 }
301
302 /*****************************************************************************
303  * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2
304  *****************************************************************************/
305 static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source,
306                                               picture_t *p_dest )
307 {
308     /* FIXME: TODO ! */
309     msg_Err( p_vout, "I420_IUYV unimplemented, please harass <sam@zoy.org>" );
310 }
311
312 /*****************************************************************************
313  * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2
314  *****************************************************************************/
315 static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source,
316                                               picture_t *p_dest )
317 {
318     u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch
319                                       + p_dest->p->i_pitch;
320     u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch;
321     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
322     u8 *p_u = p_source->U_PIXELS;
323     u8 *p_v = p_source->V_PIXELS;
324
325     int i_x, i_y;
326
327     const int i_source_margin = p_source->p->b_margin ?
328         p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
329     const int i_dest_margin = p_dest->p->b_margin ?
330         p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
331
332     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
333     {
334         p_line1 -= 3 * p_dest->p->i_pitch;
335         p_line2 -= 3 * p_dest->p->i_pitch;
336
337         p_y1 = p_y2;
338         p_y2 += p_source->p[Y_PLANE].i_pitch;
339
340         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
341         {
342 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
343             C_YUV420_UYVY( );
344             C_YUV420_UYVY( );
345             C_YUV420_UYVY( );
346             C_YUV420_UYVY( );
347 #else
348             MMX_CALL( MMX_YUV420_UYVY );
349 #endif
350         }
351
352         p_y1 += i_source_margin;
353         p_y2 += i_source_margin;
354         p_line1 += i_dest_margin;
355         p_line2 += i_dest_margin;
356     }
357 }
358
359 /*****************************************************************************
360  * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1
361  *****************************************************************************/
362 #if defined (MODULE_NAME_IS_chroma_i420_yuy2)
363 static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source,
364                                               picture_t *p_dest )
365 {
366     u8 *p_line1, *p_line2 = p_dest->p->p_pixels;
367     u8 *p_y1, *p_y2 = p_source->Y_PIXELS;
368     u8 *p_u = p_source->U_PIXELS;
369     u8 *p_v = p_source->V_PIXELS;
370
371     int i_x, i_y;
372
373     const int i_source_margin = p_source->p->b_margin ?
374         p_source->p->i_pitch - p_source->p->i_visible_bytes : 0;
375     const int i_dest_margin = p_dest->p->b_margin ?
376         p_dest->p->i_pitch - p_dest->p->i_visible_bytes : 0;
377
378     for( i_y = p_vout->render.i_height / 2 ; i_y-- ; )
379     {
380         p_line1 = p_line2;
381         p_line2 += p_dest->p->i_pitch;
382
383         p_y1 = p_y2;
384         p_y2 += p_source->p[Y_PLANE].i_pitch;
385
386         for( i_x = p_vout->render.i_width / 8 ; i_x-- ; )
387         {
388             C_YUV420_Y211( );
389             C_YUV420_Y211( );
390         }
391
392         p_y1 += i_source_margin;
393         p_y2 += i_source_margin;
394         p_line1 += i_dest_margin;
395         p_line2 += i_dest_margin;
396     }
397 }
398 #endif
399