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