]> git.sesse.net Git - vlc/blob - modules/video_chroma/i420_rgb16.c
mediacodec: skip prerolled frames
[vlc] / modules / video_chroma / i420_rgb16.c
1 /*****************************************************************************
2  * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Damien Fouilleul <damienf@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30 #include <vlc_filter.h>
31 #include <vlc_cpu.h>
32
33 #include "i420_rgb.h"
34 #include "i420_rgb_c.h"
35
36 /*****************************************************************************
37  * SetOffset: build offset array for conversion functions
38  *****************************************************************************
39  * This function will build an offset array used in later conversion functions.
40  * It will also set horizontal and vertical scaling indicators.
41  *****************************************************************************/
42 static void SetOffset( int i_width, int i_height, int i_pic_width,
43                        int i_pic_height, bool *pb_hscale,
44                        unsigned int *pi_vscale, int *p_offset )
45 {
46     /*
47      * Prepare horizontal offset array
48      */
49     if( i_pic_width - i_width == 0 )
50     {   /* No horizontal scaling: YUV conversion is done directly to picture */
51         *pb_hscale = 0;
52     }
53     else if( i_pic_width - i_width > 0 )
54     {   /* Prepare scaling array for horizontal extension */
55         int i_scale_count = i_pic_width;
56
57         *pb_hscale = 1;
58         for( int i_x = i_width; i_x--; )
59         {
60             while( (i_scale_count -= i_width) > 0 )
61             {
62                 *p_offset++ = 0;
63             }
64             *p_offset++ = 1;
65             i_scale_count += i_pic_width;
66         }
67     }
68     else /* if( i_pic_width - i_width < 0 ) */
69     {   /* Prepare scaling array for horizontal reduction */
70         int i_scale_count = i_pic_width;
71
72         *pb_hscale = 1;
73         for( int i_x = i_pic_width; i_x--; )
74         {
75             *p_offset = 1;
76             while( (i_scale_count -= i_pic_width) > 0 )
77             {
78                 *p_offset += 1;
79             }
80             p_offset++;
81             i_scale_count += i_width;
82         }
83     }
84
85     /*
86      * Set vertical scaling indicator
87      */
88     if( i_pic_height - i_height == 0 )
89         *pi_vscale = 0;
90     else if( i_pic_height - i_height > 0 )
91         *pi_vscale = 1;
92     else /* if( i_pic_height - i_height < 0 ) */
93         *pi_vscale = -1;
94 }
95
96 /*****************************************************************************
97  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
98  *****************************************************************************
99  * Horizontal alignment needed:
100  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
101  *  - output: 1 pixel (2 bytes), margins allowed
102  * Vertical alignment needed:
103  *  - input: 2 lines (2 Y lines, 1 U/V line)
104  *  - output: 1 line
105  *****************************************************************************/
106
107 void I420_RGB16( filter_t *p_filter, picture_t *p_src, picture_t *p_dest )
108 {
109     /* We got this one from the old arguments */
110     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
111     uint8_t  *p_y   = p_src->Y_PIXELS;
112     uint8_t  *p_u   = p_src->U_PIXELS;
113     uint8_t  *p_v   = p_src->V_PIXELS;
114
115     bool  b_hscale;                         /* horizontal scaling type */
116     unsigned int i_vscale;                          /* vertical scaling type */
117     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
118
119     int         i_right_margin;
120     int         i_rewind;
121     int         i_scale_count;                       /* scale modulo counter */
122     int         i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
123     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
124     int         i_uval, i_vval;                           /* U and V samples */
125     int         i_red, i_green, i_blue;          /* U and V modified samples */
126     uint16_t *  p_yuv = p_filter->p_sys->p_rgb16;
127     uint16_t *  p_ybase;                     /* Y dependant conversion table */
128
129     /* Conversion buffer pointer */
130     uint16_t *  p_buffer_start = (uint16_t*)p_filter->p_sys->p_buffer;
131     uint16_t *  p_buffer;
132
133     /* Offset array pointer */
134     int *       p_offset_start = p_filter->p_sys->p_offset;
135     int *       p_offset;
136
137     const int i_source_margin = p_src->p[0].i_pitch
138                                  - p_src->p[0].i_visible_pitch;
139     const int i_source_margin_c = p_src->p[1].i_pitch
140                                  - p_src->p[1].i_visible_pitch;
141
142     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
143     i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
144
145     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
146      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
147      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
148     SetOffset( p_filter->fmt_in.video.i_width,
149                p_filter->fmt_in.video.i_height,
150                p_filter->fmt_out.video.i_width,
151                p_filter->fmt_out.video.i_height,
152                &b_hscale, &i_vscale, p_offset_start );
153
154     /*
155      * Perform conversion
156      */
157     i_scale_count = ( i_vscale == 1 ) ?
158                     p_filter->fmt_out.video.i_height :
159                     p_filter->fmt_in.video.i_height;
160     for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
161     {
162         p_pic_start = p_pic;
163         p_buffer = b_hscale ? p_buffer_start : p_pic;
164
165         for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
166         {
167             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
168             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
169             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
170             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
171         }
172
173         /* Here we do some unaligned reads and duplicate conversions, but
174          * at least we have all the pixels */
175         if( i_rewind )
176         {
177             p_y -= i_rewind;
178             p_u -= i_rewind >> 1;
179             p_v -= i_rewind >> 1;
180             p_buffer -= i_rewind;
181
182             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
183             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
184             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
185             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
186         }
187         SCALE_WIDTH;
188         SCALE_HEIGHT( 420, 2 );
189
190         p_y += i_source_margin;
191         if( i_y % 2 )
192         {
193             p_u += i_source_margin_c;
194             p_v += i_source_margin_c;
195         }
196     }
197 }
198
199 /*****************************************************************************
200  * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
201  *****************************************************************************
202  * Horizontal alignment needed:
203  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
204  *  - output: 1 pixel (2 bytes), margins allowed
205  * Vertical alignment needed:
206  *  - input: 2 lines (2 Y lines, 1 U/V line)
207  *  - output: 1 line
208  *****************************************************************************/
209
210 void I420_RGB32( filter_t *p_filter, picture_t *p_src, picture_t *p_dest )
211 {
212     /* We got this one from the old arguments */
213     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
214     uint8_t  *p_y   = p_src->Y_PIXELS;
215     uint8_t  *p_u   = p_src->U_PIXELS;
216     uint8_t  *p_v   = p_src->V_PIXELS;
217
218     bool  b_hscale;                         /* horizontal scaling type */
219     unsigned int i_vscale;                          /* vertical scaling type */
220     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
221
222     int         i_right_margin;
223     int         i_rewind;
224     int         i_scale_count;                       /* scale modulo counter */
225     int         i_chroma_width = p_filter->fmt_in.video.i_width / 2; /* chroma width */
226     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
227     int         i_uval, i_vval;                           /* U and V samples */
228     int         i_red, i_green, i_blue;          /* U and V modified samples */
229     uint32_t *  p_yuv = p_filter->p_sys->p_rgb32;
230     uint32_t *  p_ybase;                     /* Y dependant conversion table */
231
232     /* Conversion buffer pointer */
233     uint32_t *  p_buffer_start = (uint32_t*)p_filter->p_sys->p_buffer;
234     uint32_t *  p_buffer;
235
236     /* Offset array pointer */
237     int *       p_offset_start = p_filter->p_sys->p_offset;
238     int *       p_offset;
239
240     const int i_source_margin = p_src->p[0].i_pitch
241                                  - p_src->p[0].i_visible_pitch;
242     const int i_source_margin_c = p_src->p[1].i_pitch
243                                  - p_src->p[1].i_visible_pitch;
244
245     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
246     i_rewind = (-p_filter->fmt_in.video.i_width) & 7;
247
248     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
249      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
250      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
251     SetOffset( p_filter->fmt_in.video.i_width,
252                p_filter->fmt_in.video.i_height,
253                p_filter->fmt_out.video.i_width,
254                p_filter->fmt_out.video.i_height,
255                &b_hscale, &i_vscale, p_offset_start );
256
257     /*
258      * Perform conversion
259      */
260     i_scale_count = ( i_vscale == 1 ) ?
261                     p_filter->fmt_out.video.i_height :
262                     p_filter->fmt_in.video.i_height;
263     for( i_y = 0; i_y < p_filter->fmt_in.video.i_height; i_y++ )
264     {
265         p_pic_start = p_pic;
266         p_buffer = b_hscale ? p_buffer_start : p_pic;
267
268         for ( i_x = p_filter->fmt_in.video.i_width / 8; i_x--; )
269         {
270             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
271             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
272             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
273             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
274         }
275
276         /* Here we do some unaligned reads and duplicate conversions, but
277          * at least we have all the pixels */
278         if( i_rewind )
279         {
280             p_y -= i_rewind;
281             p_u -= i_rewind >> 1;
282             p_v -= i_rewind >> 1;
283             p_buffer -= i_rewind;
284             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
285             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
286             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
287             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
288         }
289         SCALE_WIDTH;
290         SCALE_HEIGHT( 420, 4 );
291
292         p_y += i_source_margin;
293         if( i_y % 2 )
294         {
295             p_u += i_source_margin_c;
296             p_v += i_source_margin_c;
297         }
298     }
299 }