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