]> git.sesse.net Git - vlc/blob - modules/video_chroma/yuy2_i420.c
Merge commit 'origin/1.0-bugfix'
[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_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     if( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width
80      || p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height )
81         return -1;
82
83     switch( p_filter->fmt_out.video.i_chroma )
84     {
85         case VLC_CODEC_I420:
86             switch( p_filter->fmt_in.video.i_chroma )
87             {
88                 case VLC_CODEC_YUYV:
89                     p_filter->pf_video_filter = YUY2_I420_Filter;
90                     break;
91
92                 case VLC_CODEC_YVYU:
93                     p_filter->pf_video_filter = YVYU_I420_Filter;
94                     break;
95
96                 case VLC_CODEC_UYVY:
97                     p_filter->pf_video_filter = UYVY_I420_Filter;
98                     break;
99
100                 case VLC_CODEC_CYUV:
101                     p_filter->pf_video_filter = cyuv_I420_Filter;
102                     break;
103
104                 default:
105                     return -1;
106             }
107             break;
108
109         default:
110             return -1;
111     }
112     return 0;
113 }
114
115 /* Following functions are local */
116 VIDEO_FILTER_WRAPPER( YUY2_I420 )
117 VIDEO_FILTER_WRAPPER( YVYU_I420 )
118 VIDEO_FILTER_WRAPPER( UYVY_I420 )
119 VIDEO_FILTER_WRAPPER( cyuv_I420 )
120
121 /*****************************************************************************
122  * YUY2_I420: packed YUY2 4:2:2 to planar YUV 4:2:0
123  *****************************************************************************/
124 static void YUY2_I420( filter_t *p_filter, picture_t *p_source,
125                                            picture_t *p_dest )
126 {
127     uint8_t *p_line = p_source->p->p_pixels;
128
129     uint8_t *p_y = p_dest->Y_PIXELS;
130     uint8_t *p_u = p_dest->U_PIXELS;
131     uint8_t *p_v = p_dest->V_PIXELS;
132
133     int i_x, i_y;
134
135     const int i_dest_margin = p_dest->p[0].i_pitch
136                                  - p_dest->p[0].i_visible_pitch;
137     const int i_dest_margin_c = p_dest->p[1].i_pitch
138                                  - p_dest->p[1].i_visible_pitch;
139     const int i_source_margin = p_source->p->i_pitch
140                                - p_source->p->i_visible_pitch;
141
142     bool b_skip = false;
143
144     for( i_y = p_filter->fmt_out.video.i_height ; i_y-- ; )
145     {
146         if( b_skip )
147         {
148             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
149             {
150     #define C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v )      \
151                 *p_y++ = *p_line++; p_line++; \
152                 *p_y++ = *p_line++; p_line++
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                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
157             }
158             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
159             {
160                 C_YUYV_YUV422_skip( p_line, p_y, p_u, p_v );
161             }
162         }
163         else
164         {
165             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
166             {
167     #define C_YUYV_YUV422( p_line, p_y, p_u, p_v )      \
168                 *p_y++ = *p_line++; *p_u++ = *p_line++; \
169                 *p_y++ = *p_line++; *p_v++ = *p_line++
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                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
174             }
175             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
176             {
177                 C_YUYV_YUV422( p_line, p_y, p_u, p_v );
178             }
179         }
180         p_line += i_source_margin;
181         p_y += i_dest_margin;
182         p_u += i_dest_margin_c;
183         p_v += i_dest_margin_c;
184
185         b_skip = !b_skip;
186     }
187 }
188
189 /*****************************************************************************
190  * YVYU_I420: packed YVYU 4:2:2 to planar YUV 4:2:0
191  *****************************************************************************/
192 static void YVYU_I420( filter_t *p_filter, picture_t *p_source,
193                                            picture_t *p_dest )
194 {
195     uint8_t *p_line = p_source->p->p_pixels;
196
197     uint8_t *p_y = p_dest->Y_PIXELS;
198     uint8_t *p_u = p_dest->U_PIXELS;
199     uint8_t *p_v = p_dest->V_PIXELS;
200
201     int i_x, i_y;
202
203     const int i_dest_margin = p_dest->p[0].i_pitch
204                                  - p_dest->p[0].i_visible_pitch;
205     const int i_dest_margin_c = p_dest->p[1].i_pitch
206                                  - p_dest->p[1].i_visible_pitch;
207     const int i_source_margin = p_source->p->i_pitch
208                                - p_source->p->i_visible_pitch;
209
210     bool b_skip = false;
211
212     for( i_y = p_filter->fmt_out.video.i_height ; i_y-- ; )
213     {
214         if( b_skip )
215         {
216             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
217             {
218     #define C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v )      \
219                 *p_y++ = *p_line++; p_line++; \
220                 *p_y++ = *p_line++; p_line++
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                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
225             }
226             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
227             {
228                 C_YVYU_YUV422_skip( p_line, p_y, p_u, p_v );
229             }
230         }
231         else
232         {
233             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
234             {
235     #define C_YVYU_YUV422( p_line, p_y, p_u, p_v )      \
236                 *p_y++ = *p_line++; *p_v++ = *p_line++; \
237                 *p_y++ = *p_line++; *p_u++ = *p_line++
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                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
242             }
243             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
244             {
245                 C_YVYU_YUV422( p_line, p_y, p_u, p_v );
246             }
247         }
248         p_line += i_source_margin;
249         p_y += i_dest_margin;
250         p_u += i_dest_margin_c;
251         p_v += i_dest_margin_c;
252
253         b_skip = !b_skip;
254     }
255 }
256
257 /*****************************************************************************
258  * UYVY_I420: packed UYVY 4:2:2 to planar YUV 4:2:0
259  *****************************************************************************/
260 static void UYVY_I420( filter_t *p_filter, picture_t *p_source,
261                                            picture_t *p_dest )
262 {
263     uint8_t *p_line = p_source->p->p_pixels;
264
265     uint8_t *p_y = p_dest->Y_PIXELS;
266     uint8_t *p_u = p_dest->U_PIXELS;
267     uint8_t *p_v = p_dest->V_PIXELS;
268
269     int i_x, i_y;
270
271     const int i_dest_margin = p_dest->p[0].i_pitch
272                                  - p_dest->p[0].i_visible_pitch;
273     const int i_dest_margin_c = p_dest->p[1].i_pitch
274                                  - p_dest->p[1].i_visible_pitch;
275     const int i_source_margin = p_source->p->i_pitch
276                                - p_source->p->i_visible_pitch;
277
278     bool b_skip = false;
279
280     for( i_y = p_filter->fmt_out.video.i_height ; i_y-- ; )
281     {
282         if( b_skip )
283         {
284             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
285             {
286     #define C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v )      \
287                 *p_u++ = *p_line++; p_line++; \
288                 *p_v++ = *p_line++; p_line++
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                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
293             }
294             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
295             {
296                 C_UYVY_YUV422_skip( p_line, p_y, p_u, p_v );
297             }
298         }
299         else
300         {
301             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
302             {
303     #define C_UYVY_YUV422( p_line, p_y, p_u, p_v )      \
304                 *p_u++ = *p_line++; *p_y++ = *p_line++; \
305                 *p_v++ = *p_line++; *p_y++ = *p_line++
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                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
310             }
311             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
312             {
313                 C_UYVY_YUV422( p_line, p_y, p_u, p_v );
314             }
315         }
316         p_line += i_source_margin;
317         p_y += i_dest_margin;
318         p_u += i_dest_margin_c;
319         p_v += i_dest_margin_c;
320
321         b_skip = !b_skip;
322     }
323 }
324
325 /*****************************************************************************
326  * cyuv_I420: upside-down packed UYVY 4:2:2 to planar YUV 4:2:0
327  * FIXME
328  *****************************************************************************/
329 static void cyuv_I420( filter_t *p_filter, picture_t *p_source,
330                                            picture_t *p_dest )
331 {
332     uint8_t *p_line = p_source->p->p_pixels;
333
334     uint8_t *p_y = p_dest->Y_PIXELS;
335     uint8_t *p_u = p_dest->U_PIXELS;
336     uint8_t *p_v = p_dest->V_PIXELS;
337
338     int i_x, i_y;
339
340     const int i_dest_margin = p_dest->p[0].i_pitch
341                                  - p_dest->p[0].i_visible_pitch;
342     const int i_dest_margin_c = p_dest->p[1].i_pitch
343                                  - p_dest->p[1].i_visible_pitch;
344     const int i_source_margin = p_source->p->i_pitch
345                                - p_source->p->i_visible_pitch;
346
347     bool b_skip = false;
348
349     for( i_y = p_filter->fmt_out.video.i_height ; i_y-- ; )
350     {
351         if( b_skip )
352         {
353             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
354             {
355     #define C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v )      \
356                 *p_y++ = *p_line++; p_line++; \
357                 *p_y++ = *p_line++; p_line++
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                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
362             }
363             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
364             {
365                 C_cyuv_YUV422_skip( p_line, p_y, p_u, p_v );
366             }
367         }
368         else
369         {
370             for( i_x = p_filter->fmt_out.video.i_width / 8 ; i_x-- ; )
371             {
372     #define C_cyuv_YUV422( p_line, p_y, p_u, p_v )      \
373                 *p_y++ = *p_line++; *p_v++ = *p_line++; \
374                 *p_y++ = *p_line++; *p_u++ = *p_line++
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                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
379             }
380             for( i_x = ( p_filter->fmt_out.video.i_width % 8 ) / 2; i_x-- ; )
381             {
382                 C_cyuv_YUV422( p_line, p_y, p_u, p_v );
383             }
384         }
385         p_line += i_source_margin;
386         p_y += i_dest_margin;
387         p_u += i_dest_margin_c;
388         p_v += i_dest_margin_c;
389
390         b_skip = !b_skip;
391     }
392 }