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