]> git.sesse.net Git - vlc/blob - plugins/chroma/i420_rgb16.c
13f801b7bf337ce7300567f977e8c6e9b37e96b1
[vlc] / plugins / chroma / i420_rgb16.c
1 /*****************************************************************************
2  * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  * $Id: i420_rgb16.c,v 1.6.2.1 2002/06/01 10:43:54 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <string.h>                                            /* strerror() */
29 #include <stdlib.h>                                      /* malloc(), free() */
30
31 #include <videolan/vlc.h>
32
33 #include "video.h"
34 #include "video_output.h"
35
36 #include "i420_rgb.h"
37 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
38 #   include "i420_rgb_c.h"
39 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
40 #   include "i420_rgb_mmx.h"
41 #endif
42
43 static void SetOffset( int, int, int, int, boolean_t *, int *, int * );
44
45 /*****************************************************************************
46  * I420_RGB15: color YUV 4:2:0 to RGB 15 bpp
47  *****************************************************************************
48  * Horizontal alignment needed:
49  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
50  *  - output: 1 pixel (2 bytes), margins allowed
51  * Vertical alignment needed:
52  *  - input: 2 lines (2 Y lines, 1 U/V line)
53  *  - output: 1 line
54  *****************************************************************************/
55 void _M( I420_RGB15 )( vout_thread_t *p_vout, picture_t *p_src,
56                                               picture_t *p_dest )
57 {
58     /* We got this one from the old arguments */
59     u16 *p_pic = (u16*)p_dest->p->p_pixels;
60     u8  *p_y   = p_src->Y_PIXELS;
61     u8  *p_u   = p_src->U_PIXELS;
62     u8  *p_v   = p_src->V_PIXELS;
63
64     boolean_t   b_hscale;                         /* horizontal scaling type */
65     int         i_vscale;                           /* vertical scaling type */
66     int         i_x, i_y;                 /* horizontal and vertical indexes */
67     int         i_right_margin;
68     int         i_rewind;
69     int         i_scale_count;                       /* scale modulo counter */
70     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
71     u16 *       p_pic_start;       /* beginning of the current line for copy */
72 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
73     int         i_uval, i_vval;                           /* U and V samples */
74     int         i_red, i_green, i_blue;          /* U and V modified samples */
75     u16 *       p_yuv = p_vout->chroma.p_sys->p_rgb16;
76     u16 *       p_ybase;                     /* Y dependant conversion table */
77 #endif
78
79     /* Conversion buffer pointer */
80     u16 *       p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer;
81     u16 *       p_buffer;
82
83     /* Offset array pointer */
84     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
85     int *       p_offset;
86
87     if( p_dest->p->b_margin )
88     {
89         i_right_margin = (p_dest->p->i_pitch - p_dest->p->i_visible_bytes) / 2;
90     }
91     else
92     {
93         i_right_margin = 0;
94     }
95
96     if( p_vout->render.i_width & 7 )
97     {
98         i_rewind = 8 - ( p_vout->render.i_width & 7 );
99     }
100     else
101     {
102         i_rewind = 0;
103     }
104
105     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
106      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
107      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
108     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
109                p_vout->output.i_width, p_vout->output.i_height,
110                &b_hscale, &i_vscale, p_offset_start );
111
112     /*
113      * Perform conversion
114      */
115     i_scale_count = ( i_vscale == 1 ) ?
116                     p_vout->output.i_height : p_vout->render.i_height;
117     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
118     {
119         p_pic_start = p_pic;
120         p_buffer = b_hscale ? p_buffer_start : p_pic;
121
122         for ( i_x = p_vout->render.i_width / 8; i_x--; )
123         {
124 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
125             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
126             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
127             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
128             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
129 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
130             __asm__( MMX_INIT_16
131                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
132
133             __asm__( ".align 8"
134                      MMX_YUV_MUL
135                      MMX_YUV_ADD
136                      MMX_UNPACK_15
137                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
138
139             p_y += 8;
140             p_u += 4;
141             p_v += 4;
142             p_buffer += 8;
143 #endif
144         }
145
146         /* Here we do some unaligned reads and duplicate conversions, but
147          * at least we have all the pixels */
148         if( i_rewind )
149         {
150             p_y -= i_rewind;
151             p_u -= i_rewind >> 1;
152             p_v -= i_rewind >> 1;
153             p_buffer -= i_rewind;
154 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
155             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
156             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
157             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
158             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
159 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
160             __asm__( MMX_INIT_16
161                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
162
163             __asm__( ".align 8"
164                      MMX_YUV_MUL
165                      MMX_YUV_ADD
166                      MMX_UNPACK_15
167                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
168
169             p_y += 8;
170             p_u += 4;
171             p_v += 4;
172             p_buffer += 8;
173 #endif
174         }
175         SCALE_WIDTH;
176         SCALE_HEIGHT( 420, 2 );
177     }
178 }
179
180 /*****************************************************************************
181  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
182  *****************************************************************************
183  * Horizontal alignment needed:
184  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
185  *  - output: 1 pixel (2 bytes), margins allowed
186  * Vertical alignment needed:
187  *  - input: 2 lines (2 Y lines, 1 U/V line)
188  *  - output: 1 line
189  *****************************************************************************/
190 void _M( I420_RGB16 )( vout_thread_t *p_vout, picture_t *p_src,
191                                               picture_t *p_dest )
192 {
193     /* We got this one from the old arguments */
194     u16 *p_pic = (u16*)p_dest->p->p_pixels;
195     u8  *p_y   = p_src->Y_PIXELS;
196     u8  *p_u   = p_src->U_PIXELS;
197     u8  *p_v   = p_src->V_PIXELS;
198
199     boolean_t   b_hscale;                         /* horizontal scaling type */
200     int         i_vscale;                           /* vertical scaling type */
201     int         i_x, i_y;                 /* horizontal and vertical indexes */
202     int         i_right_margin;
203     int         i_rewind;
204     int         i_scale_count;                       /* scale modulo counter */
205     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
206     u16 *       p_pic_start;       /* beginning of the current line for copy */
207 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
208     int         i_uval, i_vval;                           /* U and V samples */
209     int         i_red, i_green, i_blue;          /* U and V modified samples */
210     u16 *       p_yuv = p_vout->chroma.p_sys->p_rgb16;
211     u16 *       p_ybase;                     /* Y dependant conversion table */
212 #endif
213
214     /* Conversion buffer pointer */
215     u16 *       p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer;
216     u16 *       p_buffer;
217
218     /* Offset array pointer */
219     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
220     int *       p_offset;
221
222     if( p_dest->p->b_margin )
223     {
224         i_right_margin = (p_dest->p->i_pitch - p_dest->p->i_visible_bytes) / 2;
225     }
226     else
227     {
228         i_right_margin = 0;
229     }
230
231     if( p_vout->render.i_width & 7 )
232     {
233         i_rewind = 8 - ( p_vout->render.i_width & 7 );
234     }
235     else
236     {
237         i_rewind = 0;
238     }
239
240     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
241      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
242      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
243     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
244                p_vout->output.i_width, p_vout->output.i_height,
245                &b_hscale, &i_vscale, p_offset_start );
246
247     /*
248      * Perform conversion
249      */
250     i_scale_count = ( i_vscale == 1 ) ?
251                     p_vout->output.i_height : p_vout->render.i_height;
252     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
253     {
254         p_pic_start = p_pic;
255         p_buffer = b_hscale ? p_buffer_start : p_pic;
256
257         for ( i_x = p_vout->render.i_width / 8; i_x--; )
258         {
259 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
260             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
261             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
262             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
263             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
264 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
265             __asm__( MMX_INIT_16
266                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
267
268             __asm__( ".align 8"
269                      MMX_YUV_MUL
270                      MMX_YUV_ADD
271                      MMX_UNPACK_16
272                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
273
274             p_y += 8;
275             p_u += 4;
276             p_v += 4;
277             p_buffer += 8;
278 #endif
279         }
280
281         /* Here we do some unaligned reads and duplicate conversions, but
282          * at least we have all the pixels */
283         if( i_rewind )
284         {
285             p_y -= i_rewind;
286             p_u -= i_rewind >> 1;
287             p_v -= i_rewind >> 1;
288             p_buffer -= i_rewind;
289 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
290             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
291             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
292             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
293             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
294 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
295             __asm__( MMX_INIT_16
296                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
297
298             __asm__( ".align 8"
299                      MMX_YUV_MUL
300                      MMX_YUV_ADD
301                      MMX_UNPACK_16
302                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
303
304             p_y += 8;
305             p_u += 4;
306             p_v += 4;
307             p_buffer += 8;
308 #endif
309         }
310         SCALE_WIDTH;
311         SCALE_HEIGHT( 420, 2 );
312     }
313 }
314
315 /*****************************************************************************
316  * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
317  *****************************************************************************
318  * Horizontal alignment needed:
319  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
320  *  - output: 1 pixel (2 bytes), margins allowed
321  * Vertical alignment needed:
322  *  - input: 2 lines (2 Y lines, 1 U/V line)
323  *  - output: 1 line
324  *****************************************************************************/
325 void _M( I420_RGB32 )( vout_thread_t *p_vout, picture_t *p_src,
326                                               picture_t *p_dest )
327 {
328     /* We got this one from the old arguments */
329     u32 *p_pic = (u32*)p_dest->p->p_pixels;
330     u8  *p_y   = p_src->Y_PIXELS;
331     u8  *p_u   = p_src->U_PIXELS;
332     u8  *p_v   = p_src->V_PIXELS;
333
334     boolean_t   b_hscale;                         /* horizontal scaling type */
335     int         i_vscale;                           /* vertical scaling type */
336     int         i_x, i_y;                 /* horizontal and vertical indexes */
337     int         i_right_margin;
338     int         i_rewind;
339     int         i_scale_count;                       /* scale modulo counter */
340     int         i_chroma_width = p_vout->render.i_width / 4; /* chroma width */
341     u32 *       p_pic_start;       /* beginning of the current line for copy */
342 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
343     int         i_uval, i_vval;                           /* U and V samples */
344     int         i_red, i_green, i_blue;          /* U and V modified samples */
345     u32 *       p_yuv = p_vout->chroma.p_sys->p_rgb32;
346     u32 *       p_ybase;                     /* Y dependant conversion table */
347 #endif
348
349     /* Conversion buffer pointer */
350     u32 *       p_buffer_start = (u32*)p_vout->chroma.p_sys->p_buffer;
351     u32 *       p_buffer;
352
353     /* Offset array pointer */
354     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
355     int *       p_offset;
356
357     if( p_dest->p->b_margin )
358     {
359         i_right_margin = (p_dest->p->i_pitch - p_dest->p->i_visible_bytes) / 2;
360     }
361     else
362     {
363         i_right_margin = 0;
364     }
365
366     if( p_vout->render.i_width & 7 )
367     {
368         i_rewind = 8 - ( p_vout->render.i_width & 7 );
369     }
370     else
371     {
372         i_rewind = 0;
373     }
374
375     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
376      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
377      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
378     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
379                p_vout->output.i_width, p_vout->output.i_height,
380                &b_hscale, &i_vscale, p_offset_start );
381
382     /*
383      * Perform conversion
384      */
385     i_scale_count = ( i_vscale == 1 ) ?
386                     p_vout->output.i_height : p_vout->render.i_height;
387     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
388     {
389         p_pic_start = p_pic;
390         p_buffer = b_hscale ? p_buffer_start : p_pic;
391
392         for ( i_x = p_vout->render.i_width / 8; i_x--; )
393         {
394 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
395             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
396             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
397             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
398             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
399 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
400             __asm__( MMX_INIT_32
401                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
402
403             __asm__( ".align 8"
404                      MMX_YUV_MUL
405                      MMX_YUV_ADD
406                      MMX_UNPACK_32
407                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
408
409             p_y += 8;
410             p_u += 4;
411             p_v += 4;
412             p_buffer += 8;
413 #endif
414         }
415
416         /* Here we do some unaligned reads and duplicate conversions, but
417          * at least we have all the pixels */
418         if( i_rewind )
419         {
420             p_y -= i_rewind;
421             p_u -= i_rewind >> 1;
422             p_v -= i_rewind >> 1;
423             p_buffer -= i_rewind;
424 #if defined (MODULE_NAME_IS_chroma_i420_rgb)
425             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
426             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
427             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
428             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
429 #elif defined (MODULE_NAME_IS_chroma_i420_rgb_mmx)
430             __asm__( MMX_INIT_32
431                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
432
433             __asm__( ".align 8"
434                      MMX_YUV_MUL
435                      MMX_YUV_ADD
436                      MMX_UNPACK_32
437                      : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) );
438
439             p_y += 8;
440             p_u += 4;
441             p_v += 4;
442             p_buffer += 8;
443 #endif
444         }
445         SCALE_WIDTH;
446         SCALE_HEIGHT( 420, 4 );
447     }
448 }
449
450 /* Following functions are local */
451
452 /*****************************************************************************
453  * SetOffset: build offset array for conversion functions
454  *****************************************************************************
455  * This function will build an offset array used in later conversion functions.
456  * It will also set horizontal and vertical scaling indicators.
457  *****************************************************************************/
458 static void SetOffset( int i_width, int i_height, int i_pic_width,
459                        int i_pic_height, boolean_t *pb_hscale,
460                        int *pi_vscale, int *p_offset )
461 {
462     int i_x;                                    /* x position in destination */
463     int i_scale_count;                                     /* modulo counter */
464
465     /*
466      * Prepare horizontal offset array
467      */
468     if( i_pic_width - i_width == 0 )
469     {
470         /* No horizontal scaling: YUV conversion is done directly to picture */
471         *pb_hscale = 0;
472     }
473     else if( i_pic_width - i_width > 0 )
474     {
475         /* Prepare scaling array for horizontal extension */
476         *pb_hscale = 1;
477         i_scale_count = i_pic_width;
478         for( i_x = i_width; i_x--; )
479         {
480             while( (i_scale_count -= i_width) > 0 )
481             {
482                 *p_offset++ = 0;
483             }
484             *p_offset++ = 1;
485             i_scale_count += i_pic_width;
486         }
487     }
488     else /* if( i_pic_width - i_width < 0 ) */
489     {
490         /* Prepare scaling array for horizontal reduction */
491         *pb_hscale = 1;
492         i_scale_count = i_width;
493         for( i_x = i_pic_width; i_x--; )
494         {
495             *p_offset = 1;
496             while( (i_scale_count -= i_pic_width) > 0 )
497             {
498                 *p_offset += 1;
499             }
500             p_offset++;
501             i_scale_count += i_width;
502         }
503     }
504
505     /*
506      * Set vertical scaling indicator
507      */
508     if( i_pic_height - i_height == 0 )
509     {
510         *pi_vscale = 0;
511     }
512     else if( i_pic_height - i_height > 0 )
513     {
514         *pi_vscale = 1;
515     }
516     else /* if( i_pic_height - i_height < 0 ) */
517     {
518         *pi_vscale = -1;
519     }
520 }
521