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