Three new chroma converters:
[vlc.git] / modules / video_chroma / yuy2_i420.c
1 /*****************************************************************************
2  * yuy2_i420.c : Packed YUV 4:2:2 to Planar YUV conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan dot 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30
31 #define SRC_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,cyuv"
32 #define DEST_FOURCC  "I420"
33
34 /*****************************************************************************
35  * Local and extern prototypes.
36  *****************************************************************************/
37 static int  Activate ( vlc_object_t * );
38
39 static void YUY2_I420           ( vout_thread_t *, picture_t *, picture_t * );
40 static void YVYU_I420           ( vout_thread_t *, picture_t *, picture_t * );
41 static void UYVY_I420           ( vout_thread_t *, picture_t *, picture_t * );
42 static void cyuv_I420           ( vout_thread_t *, picture_t *, picture_t * );
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 vlc_module_begin();
48     set_description( _("Conversions from " SRC_FOURCC " to " DEST_FOURCC) );
49     set_capability( "chroma", 80 );
50     set_callbacks( Activate, NULL );
51 vlc_module_end();
52
53 /*****************************************************************************
54  * Activate: allocate a chroma function
55  *****************************************************************************
56  * This function allocates and initializes a chroma function
57  *****************************************************************************/
58 static int Activate( vlc_object_t *p_this )
59 {
60     vout_thread_t *p_vout = (vout_thread_t *)p_this;
61
62     if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 )
63     {
64         return -1;
65     }
66
67     switch( p_vout->output.i_chroma )
68     {
69         case VLC_FOURCC('I','4','2','0'):
70             switch( p_vout->render.i_chroma )
71             {
72                 case VLC_FOURCC('Y','U','Y','2'):
73                 case VLC_FOURCC('Y','U','N','V'):
74                     p_vout->chroma.pf_convert = YUY2_I420;
75                     break;
76
77                 case VLC_FOURCC('Y','V','Y','U'):
78                     p_vout->chroma.pf_convert = YVYU_I420;
79                     break;
80
81                 case VLC_FOURCC('U','Y','V','Y'):
82                 case VLC_FOURCC('U','Y','N','V'):
83                 case VLC_FOURCC('Y','4','2','2'):
84                     p_vout->chroma.pf_convert = UYVY_I420;
85                     break;
86
87                 case VLC_FOURCC('c','y','u','v'):
88                     p_vout->chroma.pf_convert = cyuv_I420;
89                     break;
90
91                 default:
92                     return -1;
93             }
94             break;
95
96         default:
97             return -1;
98     }
99     return 0;
100 }
101
102 /* Following functions are local */
103
104 /*****************************************************************************
105  * YUY2_I420: packed YUY2 4:2:2 to planar YUV 4:2:0
106  *****************************************************************************/
107 static void YUY2_I420( vout_thread_t *p_vout, picture_t *p_source,
108                                               picture_t *p_dest )
109 {
110     uint8_t *p_line = p_source->p->p_pixels;
111
112     uint8_t *p_y = p_dest->Y_PIXELS;
113     uint8_t *p_u = p_dest->U_PIXELS;
114     uint8_t *p_v = p_dest->V_PIXELS;
115
116     int i_x, i_y;
117
118     const int i_dest_margin = p_dest->p[0].i_pitch
119                                  - p_dest->p[0].i_visible_pitch;
120     const int i_dest_margin_c = p_dest->p[1].i_pitch
121                                  - p_dest->p[1].i_visible_pitch;
122     const int i_source_margin = p_source->p->i_pitch
123                                - p_source->p->i_visible_pitch;
124
125     vlc_bool_t b_skip = VLC_FALSE;
126
127     for( i_y = p_vout->output.i_height ; i_y-- ; )
128     {
129         if( b_skip )
130         {
131             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
132             {
133     #define C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v )      \
134                 *p_y++ = *p_line++; p_line++; \
135                 *p_y++ = *p_line++; p_line++
136                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
137                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
138                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
139                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
140             }
141             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
142             {
143                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
144             }
145         }
146         else
147         {
148             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
149             {
150     #define C_YUYV_YUV422( p_line, p_y, p_u, p_v )      \
151                 *p_y++ = *p_line++; *p_u++ = *p_line++; \
152                 *p_y++ = *p_line++; *p_v++ = *p_line++
153                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
154                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
155                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
156                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
157             }
158             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
159             {
160                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
161             }
162         }
163         p_line += i_source_margin;
164         p_y += i_dest_margin;
165         p_u += i_dest_margin_c;
166         p_v += i_dest_margin_c;
167
168         b_skip = !b_skip;
169     }
170 }
171
172 /*****************************************************************************
173  * YVYU_I420: packed YVYU 4:2:2 to planar YUV 4:2:0
174  *****************************************************************************/
175 static void YVYU_I420( vout_thread_t *p_vout, picture_t *p_source,
176                                               picture_t *p_dest )
177 {
178     uint8_t *p_line = p_source->p->p_pixels;
179
180     uint8_t *p_y = p_dest->Y_PIXELS;
181     uint8_t *p_u = p_dest->U_PIXELS;
182     uint8_t *p_v = p_dest->V_PIXELS;
183
184     int i_x, i_y;
185
186     const int i_dest_margin = p_dest->p[0].i_pitch
187                                  - p_dest->p[0].i_visible_pitch;
188     const int i_dest_margin_c = p_dest->p[1].i_pitch
189                                  - p_dest->p[1].i_visible_pitch;
190     const int i_source_margin = p_source->p->i_pitch
191                                - p_source->p->i_visible_pitch;
192
193     vlc_bool_t b_skip = VLC_FALSE;
194
195     for( i_y = p_vout->output.i_height ; i_y-- ; )
196     {
197         if( b_skip )
198         {
199             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
200             {
201     #define C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v )      \
202                 *p_y++ = *p_line++; p_line++; \
203                 *p_y++ = *p_line++; p_line++
204                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
205                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
206                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
207                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
208             }
209             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
210             {
211                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
212             }
213         }
214         else
215         {
216             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
217             {
218     #define C_YVYU_YUV422( p_line, p_y, p_u, p_v )      \
219                 *p_y++ = *p_line++; *p_v++ = *p_line++; \
220                 *p_y++ = *p_line++; *p_u++ = *p_line++
221                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
222                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
223                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
224                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
225             }
226             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
227             {
228                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
229             }
230         }
231         p_line += i_source_margin;
232         p_y += i_dest_margin;
233         p_u += i_dest_margin_c;
234         p_v += i_dest_margin_c;
235
236         b_skip = !b_skip;
237     }
238 }
239
240 /*****************************************************************************
241  * UYVY_I420: packed UYVY 4:2:2 to planar YUV 4:2:0
242  *****************************************************************************/
243 static void UYVY_I420( vout_thread_t *p_vout, picture_t *p_source,
244                                               picture_t *p_dest )
245 {
246     uint8_t *p_line = p_source->p->p_pixels;
247
248     uint8_t *p_y = p_dest->Y_PIXELS;
249     uint8_t *p_u = p_dest->U_PIXELS;
250     uint8_t *p_v = p_dest->V_PIXELS;
251
252     int i_x, i_y;
253
254     const int i_dest_margin = p_dest->p[0].i_pitch
255                                  - p_dest->p[0].i_visible_pitch;
256     const int i_dest_margin_c = p_dest->p[1].i_pitch
257                                  - p_dest->p[1].i_visible_pitch;
258     const int i_source_margin = p_source->p->i_pitch
259                                - p_source->p->i_visible_pitch;
260
261     vlc_bool_t b_skip = VLC_FALSE;
262
263     for( i_y = p_vout->output.i_height ; i_y-- ; )
264     {
265         if( b_skip )
266         {
267             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
268             {
269     #define C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v )      \
270                 *p_u++ = *p_line++; p_line++; \
271                 *p_v++ = *p_line++; p_line++
272                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
273                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
274                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
275                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
276             }
277             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
278             {
279                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
280             }
281         }
282         else
283         {
284             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
285             {
286     #define C_UYVY_YUV422( p_line, p_y, p_u, p_v )      \
287                 *p_u++ = *p_line++; *p_y++ = *p_line++; \
288                 *p_v++ = *p_line++; *p_y++ = *p_line++
289                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
290                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
291                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
292                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
293             }
294             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
295             {
296                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
297             }
298         }
299         p_line += i_source_margin;
300         p_y += i_dest_margin;
301         p_u += i_dest_margin_c;
302         p_v += i_dest_margin_c;
303
304         b_skip = !b_skip;
305     }
306 }
307
308 /*****************************************************************************
309  * cyuv_I420: upside-down packed UYVY 4:2:2 to planar YUV 4:2:0
310  * FIXME
311  *****************************************************************************/
312 static void cyuv_I420( vout_thread_t *p_vout, picture_t *p_source,
313                                               picture_t *p_dest )
314 {
315     uint8_t *p_line = p_source->p->p_pixels;
316
317     uint8_t *p_y = p_dest->Y_PIXELS;
318     uint8_t *p_u = p_dest->U_PIXELS;
319     uint8_t *p_v = p_dest->V_PIXELS;
320
321     int i_x, i_y;
322
323     const int i_dest_margin = p_dest->p[0].i_pitch
324                                  - p_dest->p[0].i_visible_pitch;
325     const int i_dest_margin_c = p_dest->p[1].i_pitch
326                                  - p_dest->p[1].i_visible_pitch;
327     const int i_source_margin = p_source->p->i_pitch
328                                - p_source->p->i_visible_pitch;
329
330     vlc_bool_t b_skip = VLC_FALSE;
331
332     for( i_y = p_vout->output.i_height ; i_y-- ; )
333     {
334         if( b_skip )
335         {
336             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
337             {
338     #define C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v )      \
339                 *p_y++ = *p_line++; p_line++; \
340                 *p_y++ = *p_line++; p_line++
341                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
342                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
343                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
344                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
345             }
346             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
347             {
348                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
349             }
350         }
351         else
352         {
353             for( i_x = p_vout->output.i_width / 8 ; i_x-- ; )
354             {
355     #define C_cyuv_YUV422( p_line, p_y, p_u, p_v )      \
356                 *p_y++ = *p_line++; *p_v++ = *p_line++; \
357                 *p_y++ = *p_line++; *p_u++ = *p_line++
358                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
359                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
360                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
361                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
362             }
363             for( i_x = ( p_vout->output.i_width % 8 ) / 2; i_x-- ; )
364             {
365                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
366             }
367         }
368         p_line += i_source_margin;
369         p_y += i_dest_margin;
370         p_u += i_dest_margin_c;
371         p_v += i_dest_margin_c;
372
373         b_skip = !b_skip;
374     }
375 }