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