GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* Copyright 2011 Stefano Sabatini <stefano.sabatini-lala poste it> |
||
3 |
* Copyright 2012 Nicolas George <nicolas.george normalesup org> |
||
4 |
* |
||
5 |
* This file is part of FFmpeg. |
||
6 |
* |
||
7 |
* FFmpeg is free software; you can redistribute it and/or |
||
8 |
* modify it under the terms of the GNU Lesser General Public |
||
9 |
* License as published by the Free Software Foundation; either |
||
10 |
* version 2.1 of the License, or (at your option) any later version. |
||
11 |
* |
||
12 |
* FFmpeg is distributed in the hope that it will be useful, |
||
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 |
* Lesser General Public License for more details. |
||
16 |
* |
||
17 |
* You should have received a copy of the GNU Lesser General Public |
||
18 |
* License along with FFmpeg; if not, write to the Free Software |
||
19 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 |
*/ |
||
21 |
|||
22 |
#include <string.h> |
||
23 |
|||
24 |
#include "libavutil/avassert.h" |
||
25 |
#include "libavutil/avutil.h" |
||
26 |
#include "libavutil/colorspace.h" |
||
27 |
#include "libavutil/intreadwrite.h" |
||
28 |
#include "libavutil/mem.h" |
||
29 |
#include "libavutil/pixdesc.h" |
||
30 |
#include "drawutils.h" |
||
31 |
#include "formats.h" |
||
32 |
|||
33 |
enum { RED = 0, GREEN, BLUE, ALPHA }; |
||
34 |
|||
35 |
47733 |
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt) |
|
36 |
{ |
||
37 |
✓✓✓✓ ✓✓ |
47733 |
switch (pix_fmt) { |
38 |
7 |
case AV_PIX_FMT_0RGB: |
|
39 |
7 |
case AV_PIX_FMT_ARGB: rgba_map[ALPHA] = 0; rgba_map[RED ] = 1; rgba_map[GREEN] = 2; rgba_map[BLUE ] = 3; break; |
|
40 |
5 |
case AV_PIX_FMT_0BGR: |
|
41 |
5 |
case AV_PIX_FMT_ABGR: rgba_map[ALPHA] = 0; rgba_map[BLUE ] = 1; rgba_map[GREEN] = 2; rgba_map[RED ] = 3; break; |
|
42 |
47638 |
case AV_PIX_FMT_RGB48LE: |
|
43 |
case AV_PIX_FMT_RGB48BE: |
||
44 |
case AV_PIX_FMT_RGBA64BE: |
||
45 |
case AV_PIX_FMT_RGBA64LE: |
||
46 |
case AV_PIX_FMT_RGB0: |
||
47 |
case AV_PIX_FMT_RGBA: |
||
48 |
47638 |
case AV_PIX_FMT_RGB24: rgba_map[RED ] = 0; rgba_map[GREEN] = 1; rgba_map[BLUE ] = 2; rgba_map[ALPHA] = 3; break; |
|
49 |
11 |
case AV_PIX_FMT_BGR48LE: |
|
50 |
case AV_PIX_FMT_BGR48BE: |
||
51 |
case AV_PIX_FMT_BGRA64BE: |
||
52 |
case AV_PIX_FMT_BGRA64LE: |
||
53 |
case AV_PIX_FMT_BGRA: |
||
54 |
case AV_PIX_FMT_BGR0: |
||
55 |
11 |
case AV_PIX_FMT_BGR24: rgba_map[BLUE ] = 0; rgba_map[GREEN] = 1; rgba_map[RED ] = 2; rgba_map[ALPHA] = 3; break; |
|
56 |
31 |
case AV_PIX_FMT_GBRP9LE: |
|
57 |
case AV_PIX_FMT_GBRP9BE: |
||
58 |
case AV_PIX_FMT_GBRP10LE: |
||
59 |
case AV_PIX_FMT_GBRP10BE: |
||
60 |
case AV_PIX_FMT_GBRP12LE: |
||
61 |
case AV_PIX_FMT_GBRP12BE: |
||
62 |
case AV_PIX_FMT_GBRP14LE: |
||
63 |
case AV_PIX_FMT_GBRP14BE: |
||
64 |
case AV_PIX_FMT_GBRP16LE: |
||
65 |
case AV_PIX_FMT_GBRP16BE: |
||
66 |
case AV_PIX_FMT_GBRAP: |
||
67 |
case AV_PIX_FMT_GBRAP10LE: |
||
68 |
case AV_PIX_FMT_GBRAP10BE: |
||
69 |
case AV_PIX_FMT_GBRAP12LE: |
||
70 |
case AV_PIX_FMT_GBRAP12BE: |
||
71 |
case AV_PIX_FMT_GBRAP16LE: |
||
72 |
case AV_PIX_FMT_GBRAP16BE: |
||
73 |
31 |
case AV_PIX_FMT_GBRP: rgba_map[GREEN] = 0; rgba_map[BLUE ] = 1; rgba_map[RED ] = 2; rgba_map[ALPHA] = 3; break; |
|
74 |
41 |
default: /* unsupported */ |
|
75 |
41 |
return AVERROR(EINVAL); |
|
76 |
} |
||
77 |
47692 |
return 0; |
|
78 |
} |
||
79 |
|||
80 |
int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4], |
||
81 |
enum AVPixelFormat pix_fmt, uint8_t rgba_color[4], |
||
82 |
int *is_packed_rgba, uint8_t rgba_map_ptr[4]) |
||
83 |
{ |
||
84 |
uint8_t rgba_map[4] = {0}; |
||
85 |
int i; |
||
86 |
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt); |
||
87 |
int hsub; |
||
88 |
|||
89 |
av_assert0(pix_desc); |
||
90 |
|||
91 |
hsub = pix_desc->log2_chroma_w; |
||
92 |
|||
93 |
*is_packed_rgba = ff_fill_rgba_map(rgba_map, pix_fmt) >= 0; |
||
94 |
|||
95 |
if (*is_packed_rgba) { |
||
96 |
pixel_step[0] = (av_get_bits_per_pixel(pix_desc))>>3; |
||
97 |
for (i = 0; i < 4; i++) |
||
98 |
dst_color[rgba_map[i]] = rgba_color[i]; |
||
99 |
|||
100 |
line[0] = av_malloc_array(w, pixel_step[0]); |
||
101 |
if (!line[0]) |
||
102 |
return AVERROR(ENOMEM); |
||
103 |
for (i = 0; i < w; i++) |
||
104 |
memcpy(line[0] + i * pixel_step[0], dst_color, pixel_step[0]); |
||
105 |
if (rgba_map_ptr) |
||
106 |
memcpy(rgba_map_ptr, rgba_map, sizeof(rgba_map[0]) * 4); |
||
107 |
} else { |
||
108 |
int plane; |
||
109 |
|||
110 |
dst_color[0] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]); |
||
111 |
dst_color[1] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0); |
||
112 |
dst_color[2] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0); |
||
113 |
dst_color[3] = rgba_color[3]; |
||
114 |
|||
115 |
for (plane = 0; plane < 4; plane++) { |
||
116 |
int line_size; |
||
117 |
int hsub1 = (plane == 1 || plane == 2) ? hsub : 0; |
||
118 |
|||
119 |
pixel_step[plane] = 1; |
||
120 |
line_size = AV_CEIL_RSHIFT(w, hsub1) * pixel_step[plane]; |
||
121 |
line[plane] = av_malloc(line_size); |
||
122 |
if (!line[plane]) { |
||
123 |
while(plane && line[plane-1]) |
||
124 |
av_freep(&line[--plane]); |
||
125 |
return AVERROR(ENOMEM); |
||
126 |
} |
||
127 |
memset(line[plane], dst_color[plane], line_size); |
||
128 |
} |
||
129 |
} |
||
130 |
|||
131 |
return 0; |
||
132 |
} |
||
133 |
|||
134 |
void ff_draw_rectangle(uint8_t *dst[4], int dst_linesize[4], |
||
135 |
uint8_t *src[4], int pixelstep[4], |
||
136 |
int hsub, int vsub, int x, int y, int w, int h) |
||
137 |
{ |
||
138 |
int i, plane; |
||
139 |
uint8_t *p; |
||
140 |
|||
141 |
for (plane = 0; plane < 4 && dst[plane]; plane++) { |
||
142 |
int hsub1 = plane == 1 || plane == 2 ? hsub : 0; |
||
143 |
int vsub1 = plane == 1 || plane == 2 ? vsub : 0; |
||
144 |
int width = AV_CEIL_RSHIFT(w, hsub1); |
||
145 |
int height = AV_CEIL_RSHIFT(h, vsub1); |
||
146 |
|||
147 |
p = dst[plane] + (y >> vsub1) * dst_linesize[plane]; |
||
148 |
for (i = 0; i < height; i++) { |
||
149 |
memcpy(p + (x >> hsub1) * pixelstep[plane], |
||
150 |
src[plane], width * pixelstep[plane]); |
||
151 |
p += dst_linesize[plane]; |
||
152 |
} |
||
153 |
} |
||
154 |
} |
||
155 |
|||
156 |
void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4], |
||
157 |
uint8_t *src[4], int src_linesize[4], int pixelstep[4], |
||
158 |
int hsub, int vsub, int x, int y, int y2, int w, int h) |
||
159 |
{ |
||
160 |
int i, plane; |
||
161 |
uint8_t *p; |
||
162 |
|||
163 |
for (plane = 0; plane < 4 && dst[plane]; plane++) { |
||
164 |
int hsub1 = plane == 1 || plane == 2 ? hsub : 0; |
||
165 |
int vsub1 = plane == 1 || plane == 2 ? vsub : 0; |
||
166 |
int width = AV_CEIL_RSHIFT(w, hsub1); |
||
167 |
int height = AV_CEIL_RSHIFT(h, vsub1); |
||
168 |
|||
169 |
p = dst[plane] + (y >> vsub1) * dst_linesize[plane]; |
||
170 |
for (i = 0; i < height; i++) { |
||
171 |
memcpy(p + (x >> hsub1) * pixelstep[plane], |
||
172 |
src[plane] + src_linesize[plane]*(i+(y2>>vsub1)), width * pixelstep[plane]); |
||
173 |
p += dst_linesize[plane]; |
||
174 |
} |
||
175 |
} |
||
176 |
} |
||
177 |
|||
178 |
26123 |
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) |
|
179 |
{ |
||
180 |
26123 |
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); |
|
181 |
const AVComponentDescriptor *c; |
||
182 |
26123 |
unsigned i, nb_planes = 0; |
|
183 |
26123 |
int pixelstep[MAX_PLANES] = { 0 }; |
|
184 |
26123 |
int full_range = 0; |
|
185 |
|||
186 |
✓✗✗✓ |
26123 |
if (!desc || !desc->name) |
187 |
return AVERROR(EINVAL); |
||
188 |
✓✓ | 26123 |
if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA)) |
189 |
12838 |
return AVERROR(ENOSYS); |
|
190 |
✓✓✓✗ ✓✓✗✓ |
13285 |
if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE || format == AV_PIX_FMT_P016LE || format == AV_PIX_FMT_P016BE) |
191 |
262 |
return AVERROR(ENOSYS); |
|
192 |
✓✓✓✓ ✓✓✓✓ |
13023 |
if (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P || format == AV_PIX_FMT_YUVJ444P || |
193 |
✓✓ | 12490 |
format == AV_PIX_FMT_YUVJ411P || format == AV_PIX_FMT_YUVJ440P) |
194 |
666 |
full_range = 1; |
|
195 |
✓✓ | 46232 |
for (i = 0; i < desc->nb_components; i++) { |
196 |
35829 |
c = &desc->comp[i]; |
|
197 |
/* for now, only 8-16 bits formats */ |
||
198 |
✓✓✗✓ |
35829 |
if (c->depth < 8 || c->depth > 16) |
199 |
1310 |
return AVERROR(ENOSYS); |
|
200 |
✗✓ | 34519 |
if (desc->flags & AV_PIX_FMT_FLAG_BE) |
201 |
return AVERROR(ENOSYS); |
||
202 |
✗✓ | 34519 |
if (c->plane >= MAX_PLANES) |
203 |
return AVERROR(ENOSYS); |
||
204 |
/* strange interleaving */ |
||
205 |
✓✓ | 34519 |
if (pixelstep[c->plane] != 0 && |
206 |
✓✓ | 5704 |
pixelstep[c->plane] != c->step) |
207 |
655 |
return AVERROR(ENOSYS); |
|
208 |
✓✓ | 33864 |
if (pixelstep[c->plane] == 6 && |
209 |
✓✓ | 526 |
c->depth == 16) |
210 |
262 |
return AVERROR(ENOSYS); |
|
211 |
33602 |
pixelstep[c->plane] = c->step; |
|
212 |
✓✓ | 33602 |
if (pixelstep[c->plane] >= 8) |
213 |
393 |
return AVERROR(ENOSYS); |
|
214 |
33209 |
nb_planes = FFMAX(nb_planes, c->plane + 1); |
|
215 |
} |
||
216 |
10403 |
memset(draw, 0, sizeof(*draw)); |
|
217 |
10403 |
draw->desc = desc; |
|
218 |
10403 |
draw->format = format; |
|
219 |
10403 |
draw->nb_planes = nb_planes; |
|
220 |
10403 |
draw->flags = flags; |
|
221 |
10403 |
draw->full_range = full_range; |
|
222 |
10403 |
memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep)); |
|
223 |
10403 |
draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w; |
|
224 |
10403 |
draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h; |
|
225 |
✓✓✓✗ ✓✓ |
39496 |
for (i = 0; i < (desc->nb_components - !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(flags & FF_DRAW_PROCESS_ALPHA))); i++) |
226 |
29093 |
draw->comp_mask[desc->comp[i].plane] |= |
|
227 |
29093 |
1 << desc->comp[i].offset; |
|
228 |
10403 |
return 0; |
|
229 |
} |
||
230 |
|||
231 |
143811 |
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4]) |
|
232 |
{ |
||
233 |
unsigned i; |
||
234 |
uint8_t rgba_map[4]; |
||
235 |
|||
236 |
✓✗ | 143811 |
if (rgba != color->rgba) |
237 |
143811 |
memcpy(color->rgba, rgba, sizeof(color->rgba)); |
|
238 |
✓✓✓✓ |
191449 |
if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && |
239 |
47638 |
ff_fill_rgba_map(rgba_map, draw->format) >= 0) { |
|
240 |
✓✓ | 47637 |
if (draw->nb_planes == 1) { |
241 |
✓✓ | 238115 |
for (i = 0; i < 4; i++) { |
242 |
190492 |
color->comp[0].u8[rgba_map[i]] = rgba[i]; |
|
243 |
✗✓ | 190492 |
if (draw->desc->comp[rgba_map[i]].depth > 8) { |
244 |
color->comp[0].u16[rgba_map[i]] = color->comp[0].u8[rgba_map[i]] << 8; |
||
245 |
} |
||
246 |
} |
||
247 |
} else { |
||
248 |
✓✓ | 70 |
for (i = 0; i < 4; i++) { |
249 |
56 |
color->comp[rgba_map[i]].u8[0] = rgba[i]; |
|
250 |
✓✓ | 56 |
if (draw->desc->comp[rgba_map[i]].depth > 8) |
251 |
27 |
color->comp[rgba_map[i]].u16[0] = color->comp[rgba_map[i]].u8[0] << (draw->desc->comp[rgba_map[i]].depth - 8); |
|
252 |
} |
||
253 |
} |
||
254 |
✓✓ | 96174 |
} else if (draw->nb_planes >= 2) { |
255 |
/* assume YUV */ |
||
256 |
96162 |
const AVPixFmtDescriptor *desc = draw->desc; |
|
257 |
✓✓ | 96162 |
color->comp[desc->comp[0].plane].u8[desc->comp[0].offset] = draw->full_range ? RGB_TO_Y_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]); |
258 |
✓✓ | 96162 |
color->comp[desc->comp[1].plane].u8[desc->comp[1].offset] = draw->full_range ? RGB_TO_U_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0); |
259 |
✓✓ | 96162 |
color->comp[desc->comp[2].plane].u8[desc->comp[2].offset] = draw->full_range ? RGB_TO_V_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0); |
260 |
96162 |
color->comp[3].u8[0] = rgba[3]; |
|
261 |
#define EXPAND(compn) \ |
||
262 |
if (desc->comp[compn].depth > 8) \ |
||
263 |
color->comp[desc->comp[compn].plane].u16[desc->comp[compn].offset] = \ |
||
264 |
color->comp[desc->comp[compn].plane].u8[desc->comp[compn].offset] << \ |
||
265 |
(draw->desc->comp[compn].depth + draw->desc->comp[compn].shift - 8) |
||
266 |
✓✓ | 96162 |
EXPAND(3); |
267 |
✓✓ | 96162 |
EXPAND(2); |
268 |
✓✓ | 96162 |
EXPAND(1); |
269 |
✓✓ | 96162 |
EXPAND(0); |
270 |
✓✓✓✓ |
12 |
} else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A || |
271 |
✓✓✓✓ |
8 |
draw->format == AV_PIX_FMT_GRAY16LE || draw->format == AV_PIX_FMT_YA16LE || |
272 |
✓✓ | 6 |
draw->format == AV_PIX_FMT_GRAY9LE || |
273 |
✓✓ | 5 |
draw->format == AV_PIX_FMT_GRAY10LE || |
274 |
✓✓ | 4 |
draw->format == AV_PIX_FMT_GRAY12LE || |
275 |
✓✓ | 13 |
draw->format == AV_PIX_FMT_GRAY14LE) { |
276 |
10 |
const AVPixFmtDescriptor *desc = draw->desc; |
|
277 |
10 |
color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]); |
|
278 |
✓✓ | 10 |
EXPAND(0); |
279 |
10 |
color->comp[1].u8[0] = rgba[3]; |
|
280 |
✓✓ | 10 |
EXPAND(1); |
281 |
} else { |
||
282 |
2 |
av_log(NULL, AV_LOG_WARNING, |
|
283 |
2 |
"Color conversion not implemented for %s\n", draw->desc->name); |
|
284 |
2 |
memset(color, 128, sizeof(*color)); |
|
285 |
} |
||
286 |
143811 |
} |
|
287 |
|||
288 |
391682 |
static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[], |
|
289 |
int plane, int x, int y) |
||
290 |
{ |
||
291 |
391682 |
return data[plane] + |
|
292 |
783364 |
(y >> draw->vsub[plane]) * linesize[plane] + |
|
293 |
391682 |
(x >> draw->hsub[plane]) * draw->pixelstep[plane]; |
|
294 |
} |
||
295 |
|||
296 |
37 |
void ff_copy_rectangle2(FFDrawContext *draw, |
|
297 |
uint8_t *dst[], int dst_linesize[], |
||
298 |
uint8_t *src[], int src_linesize[], |
||
299 |
int dst_x, int dst_y, int src_x, int src_y, |
||
300 |
int w, int h) |
||
301 |
{ |
||
302 |
int plane, y, wp, hp; |
||
303 |
uint8_t *p, *q; |
||
304 |
|||
305 |
✓✓ | 148 |
for (plane = 0; plane < draw->nb_planes; plane++) { |
306 |
111 |
p = pointer_at(draw, src, src_linesize, plane, src_x, src_y); |
|
307 |
111 |
q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); |
|
308 |
111 |
wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane]; |
|
309 |
111 |
hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); |
|
310 |
✓✓ | 21423 |
for (y = 0; y < hp; y++) { |
311 |
21312 |
memcpy(q, p, wp); |
|
312 |
21312 |
p += src_linesize[plane]; |
|
313 |
21312 |
q += dst_linesize[plane]; |
|
314 |
} |
||
315 |
} |
||
316 |
37 |
} |
|
317 |
|||
318 |
145489 |
void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, |
|
319 |
uint8_t *dst[], int dst_linesize[], |
||
320 |
int dst_x, int dst_y, int w, int h) |
||
321 |
{ |
||
322 |
int plane, x, y, wp, hp; |
||
323 |
uint8_t *p0, *p; |
||
324 |
145489 |
FFDrawColor color_tmp = *color; |
|
325 |
|||
326 |
✓✓ | 487187 |
for (plane = 0; plane < draw->nb_planes; plane++) { |
327 |
341698 |
p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y); |
|
328 |
341698 |
wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]); |
|
329 |
341698 |
hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]); |
|
330 |
✗✓ | 341698 |
if (!hp) |
331 |
return; |
||
332 |
341698 |
p = p0; |
|
333 |
|||
334 |
if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) { |
||
335 |
for (x = 0; 2*x < draw->pixelstep[plane]; x++) |
||
336 |
color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]); |
||
337 |
} |
||
338 |
|||
339 |
/* copy first line from color */ |
||
340 |
✓✓ | 1762936 |
for (x = 0; x < wp; x++) { |
341 |
1421238 |
memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]); |
|
342 |
1421238 |
p += draw->pixelstep[plane]; |
|
343 |
} |
||
344 |
341698 |
wp *= draw->pixelstep[plane]; |
|
345 |
/* copy next lines from first line */ |
||
346 |
341698 |
p = p0 + dst_linesize[plane]; |
|
347 |
✓✓ | 6614788 |
for (y = 1; y < hp; y++) { |
348 |
6273090 |
memcpy(p, p0, wp); |
|
349 |
6273090 |
p += dst_linesize[plane]; |
|
350 |
} |
||
351 |
} |
||
352 |
} |
||
353 |
|||
354 |
/** |
||
355 |
* Clip interval [x; x+w[ within [0; wmax[. |
||
356 |
* The resulting w may be negative if the final interval is empty. |
||
357 |
* dx, if not null, return the difference between in and out value of x. |
||
358 |
*/ |
||
359 |
39148 |
static void clip_interval(int wmax, int *x, int *w, int *dx) |
|
360 |
{ |
||
361 |
✓✓ | 39148 |
if (dx) |
362 |
37924 |
*dx = 0; |
|
363 |
✗✓ | 39148 |
if (*x < 0) { |
364 |
if (dx) |
||
365 |
*dx = -*x; |
||
366 |
*w += *x; |
||
367 |
*x = 0; |
||
368 |
} |
||
369 |
✗✓ | 39148 |
if (*x + *w > wmax) |
370 |
*w = wmax - *x; |
||
371 |
39148 |
} |
|
372 |
|||
373 |
/** |
||
374 |
* Decompose w pixels starting at x |
||
375 |
* into start + (w starting at x) + end |
||
376 |
* with x and w aligned on multiples of 1<<sub. |
||
377 |
*/ |
||
378 |
99524 |
static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end) |
|
379 |
{ |
||
380 |
99524 |
int mask = (1 << sub) - 1; |
|
381 |
|||
382 |
99524 |
*start = (-*x) & mask; |
|
383 |
99524 |
*x += *start; |
|
384 |
99524 |
*start = FFMIN(*start, *w); |
|
385 |
99524 |
*w -= *start; |
|
386 |
99524 |
*end = *w & mask; |
|
387 |
99524 |
*w >>= sub; |
|
388 |
99524 |
} |
|
389 |
|||
390 |
71522 |
static int component_used(FFDrawContext *draw, int plane, int comp) |
|
391 |
{ |
||
392 |
71522 |
return (draw->comp_mask[plane] >> comp) & 1; |
|
393 |
} |
||
394 |
|||
395 |
/* If alpha is in the [ 0 ; 0x1010101 ] range, |
||
396 |
then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range, |
||
397 |
and >> 24 gives a correct rounding. */ |
||
398 |
44064 |
static void blend_line(uint8_t *dst, unsigned src, unsigned alpha, |
|
399 |
int dx, int w, unsigned hsub, int left, int right) |
||
400 |
{ |
||
401 |
44064 |
unsigned asrc = alpha * src; |
|
402 |
44064 |
unsigned tau = 0x1010101 - alpha; |
|
403 |
int x; |
||
404 |
|||
405 |
✗✓ | 44064 |
if (left) { |
406 |
unsigned suba = (left * alpha) >> hsub; |
||
407 |
*dst = (*dst * (0x1010101 - suba) + src * suba) >> 24; |
||
408 |
dst += dx; |
||
409 |
} |
||
410 |
✓✓ | 3906864 |
for (x = 0; x < w; x++) { |
411 |
3862800 |
*dst = (*dst * tau + asrc) >> 24; |
|
412 |
3862800 |
dst += dx; |
|
413 |
} |
||
414 |
✗✓ | 44064 |
if (right) { |
415 |
unsigned suba = (right * alpha) >> hsub; |
||
416 |
*dst = (*dst * (0x1010101 - suba) + src * suba) >> 24; |
||
417 |
} |
||
418 |
44064 |
} |
|
419 |
|||
420 |
11880 |
static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, |
|
421 |
int dx, int w, unsigned hsub, int left, int right) |
||
422 |
{ |
||
423 |
11880 |
unsigned asrc = alpha * src; |
|
424 |
11880 |
unsigned tau = 0x10001 - alpha; |
|
425 |
int x; |
||
426 |
|||
427 |
✗✓ | 11880 |
if (left) { |
428 |
unsigned suba = (left * alpha) >> hsub; |
||
429 |
uint16_t value = AV_RL16(dst); |
||
430 |
AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16); |
||
431 |
dst += dx; |
||
432 |
} |
||
433 |
✓✓ | 803880 |
for (x = 0; x < w; x++) { |
434 |
792000 |
uint16_t value = AV_RL16(dst); |
|
435 |
792000 |
AV_WL16(dst, (value * tau + asrc) >> 16); |
|
436 |
792000 |
dst += dx; |
|
437 |
} |
||
438 |
✗✓ | 11880 |
if (right) { |
439 |
unsigned suba = (right * alpha) >> hsub; |
||
440 |
uint16_t value = AV_RL16(dst); |
||
441 |
AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16); |
||
442 |
} |
||
443 |
11880 |
} |
|
444 |
|||
445 |
612 |
void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, |
|
446 |
uint8_t *dst[], int dst_linesize[], |
||
447 |
int dst_w, int dst_h, |
||
448 |
int x0, int y0, int w, int h) |
||
449 |
{ |
||
450 |
unsigned alpha, nb_planes, nb_comp, plane, comp; |
||
451 |
int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; |
||
452 |
uint8_t *p0, *p; |
||
453 |
|||
454 |
/* TODO optimize if alpha = 0xFF */ |
||
455 |
612 |
clip_interval(dst_w, &x0, &w, NULL); |
|
456 |
612 |
clip_interval(dst_h, &y0, &h, NULL); |
|
457 |
✓✗✓✗ ✗✓ |
612 |
if (w <= 0 || h <= 0 || !color->rgba[3]) |
458 |
return; |
||
459 |
✓✓ | 612 |
if (draw->desc->comp[0].depth <= 8) { |
460 |
/* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */ |
||
461 |
502 |
alpha = 0x10203 * color->rgba[3] + 0x2; |
|
462 |
} else { |
||
463 |
/* 0x101 * alpha is in the [ 2 ; 0x1001] range */ |
||
464 |
110 |
alpha = 0x101 * color->rgba[3] + 0x2; |
|
465 |
} |
||
466 |
✓✓✓✗ |
612 |
nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); |
467 |
612 |
nb_planes += !nb_planes; |
|
468 |
✓✓ | 2168 |
for (plane = 0; plane < nb_planes; plane++) { |
469 |
1556 |
nb_comp = draw->pixelstep[plane]; |
|
470 |
1556 |
p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); |
|
471 |
1556 |
w_sub = w; |
|
472 |
1556 |
h_sub = h; |
|
473 |
1556 |
x_sub = x0; |
|
474 |
1556 |
y_sub = y0; |
|
475 |
1556 |
subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); |
|
476 |
1556 |
subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); |
|
477 |
✓✓ | 3792 |
for (comp = 0; comp < nb_comp; comp++) { |
478 |
2236 |
const int depth = draw->desc->comp[comp].depth; |
|
479 |
|||
480 |
✓✓ | 2236 |
if (!component_used(draw, plane, comp)) |
481 |
400 |
continue; |
|
482 |
1836 |
p = p0 + comp; |
|
483 |
✗✓ | 1836 |
if (top) { |
484 |
if (depth <= 8) { |
||
485 |
blend_line(p, color->comp[plane].u8[comp], alpha >> 1, |
||
486 |
draw->pixelstep[plane], w_sub, |
||
487 |
draw->hsub[plane], left, right); |
||
488 |
} else { |
||
489 |
blend_line16(p, color->comp[plane].u16[comp], alpha >> 1, |
||
490 |
draw->pixelstep[plane], w_sub, |
||
491 |
draw->hsub[plane], left, right); |
||
492 |
} |
||
493 |
p += dst_linesize[plane]; |
||
494 |
} |
||
495 |
✓✓ | 1836 |
if (depth <= 8) { |
496 |
✓✓ | 45570 |
for (y = 0; y < h_sub; y++) { |
497 |
44064 |
blend_line(p, color->comp[plane].u8[comp], alpha, |
|
498 |
draw->pixelstep[plane], w_sub, |
||
499 |
44064 |
draw->hsub[plane], left, right); |
|
500 |
44064 |
p += dst_linesize[plane]; |
|
501 |
} |
||
502 |
} else { |
||
503 |
✓✓ | 12210 |
for (y = 0; y < h_sub; y++) { |
504 |
11880 |
blend_line16(p, color->comp[plane].u16[comp], alpha, |
|
505 |
draw->pixelstep[plane], w_sub, |
||
506 |
11880 |
draw->hsub[plane], left, right); |
|
507 |
11880 |
p += dst_linesize[plane]; |
|
508 |
} |
||
509 |
} |
||
510 |
✗✓ | 1836 |
if (bottom) { |
511 |
if (depth <= 8) { |
||
512 |
blend_line(p, color->comp[plane].u8[comp], alpha >> 1, |
||
513 |
draw->pixelstep[plane], w_sub, |
||
514 |
draw->hsub[plane], left, right); |
||
515 |
} else { |
||
516 |
blend_line16(p, color->comp[plane].u16[comp], alpha >> 1, |
||
517 |
draw->pixelstep[plane], w_sub, |
||
518 |
draw->hsub[plane], left, right); |
||
519 |
} |
||
520 |
} |
||
521 |
} |
||
522 |
} |
||
523 |
} |
||
524 |
|||
525 |
1070080 |
static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha, |
|
526 |
const uint8_t *mask, int mask_linesize, int l2depth, |
||
527 |
unsigned w, unsigned h, unsigned shift, unsigned xm0) |
||
528 |
{ |
||
529 |
1070080 |
unsigned xm, x, y, t = 0; |
|
530 |
1070080 |
unsigned xmshf = 3 - l2depth; |
|
531 |
1070080 |
unsigned xmmod = 7 >> l2depth; |
|
532 |
1070080 |
unsigned mbits = (1 << (1 << l2depth)) - 1; |
|
533 |
1070080 |
unsigned mmult = 255 / mbits; |
|
534 |
1070080 |
uint16_t value = AV_RL16(dst); |
|
535 |
|||
536 |
✓✓ | 2140160 |
for (y = 0; y < h; y++) { |
537 |
1070080 |
xm = xm0; |
|
538 |
✓✓ | 2675200 |
for (x = 0; x < w; x++) { |
539 |
1605120 |
t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) |
|
540 |
1605120 |
* mmult; |
|
541 |
1605120 |
xm++; |
|
542 |
} |
||
543 |
1070080 |
mask += mask_linesize; |
|
544 |
} |
||
545 |
1070080 |
alpha = (t >> shift) * alpha; |
|
546 |
1070080 |
AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16); |
|
547 |
1070080 |
} |
|
548 |
|||
549 |
5213952 |
static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha, |
|
550 |
const uint8_t *mask, int mask_linesize, int l2depth, |
||
551 |
unsigned w, unsigned h, unsigned shift, unsigned xm0) |
||
552 |
{ |
||
553 |
5213952 |
unsigned xm, x, y, t = 0; |
|
554 |
5213952 |
unsigned xmshf = 3 - l2depth; |
|
555 |
5213952 |
unsigned xmmod = 7 >> l2depth; |
|
556 |
5213952 |
unsigned mbits = (1 << (1 << l2depth)) - 1; |
|
557 |
5213952 |
unsigned mmult = 255 / mbits; |
|
558 |
|||
559 |
✓✓ | 11113728 |
for (y = 0; y < h; y++) { |
560 |
5899776 |
xm = xm0; |
|
561 |
✓✓ | 13217280 |
for (x = 0; x < w; x++) { |
562 |
7317504 |
t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits) |
|
563 |
7317504 |
* mmult; |
|
564 |
7317504 |
xm++; |
|
565 |
} |
||
566 |
5899776 |
mask += mask_linesize; |
|
567 |
} |
||
568 |
5213952 |
alpha = (t >> shift) * alpha; |
|
569 |
5213952 |
*dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24; |
|
570 |
5213952 |
} |
|
571 |
|||
572 |
163680 |
static void blend_line_hv16(uint8_t *dst, int dst_delta, |
|
573 |
unsigned src, unsigned alpha, |
||
574 |
const uint8_t *mask, int mask_linesize, int l2depth, int w, |
||
575 |
unsigned hsub, unsigned vsub, |
||
576 |
int xm, int left, int right, int hband) |
||
577 |
{ |
||
578 |
int x; |
||
579 |
|||
580 |
✗✓ | 163680 |
if (left) { |
581 |
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, |
||
582 |
left, hband, hsub + vsub, xm); |
||
583 |
dst += dst_delta; |
||
584 |
xm += left; |
||
585 |
} |
||
586 |
✓✓ | 1233760 |
for (x = 0; x < w; x++) { |
587 |
1070080 |
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, |
|
588 |
1070080 |
1 << hsub, hband, hsub + vsub, xm); |
|
589 |
1070080 |
dst += dst_delta; |
|
590 |
1070080 |
xm += 1 << hsub; |
|
591 |
} |
||
592 |
✗✓ | 163680 |
if (right) |
593 |
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth, |
||
594 |
right, hband, hsub + vsub, xm); |
||
595 |
163680 |
} |
|
596 |
|||
597 |
606624 |
static void blend_line_hv(uint8_t *dst, int dst_delta, |
|
598 |
unsigned src, unsigned alpha, |
||
599 |
const uint8_t *mask, int mask_linesize, int l2depth, int w, |
||
600 |
unsigned hsub, unsigned vsub, |
||
601 |
int xm, int left, int right, int hband) |
||
602 |
{ |
||
603 |
int x; |
||
604 |
|||
605 |
✗✓ | 606624 |
if (left) { |
606 |
blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, |
||
607 |
left, hband, hsub + vsub, xm); |
||
608 |
dst += dst_delta; |
||
609 |
xm += left; |
||
610 |
} |
||
611 |
✓✓ | 5820576 |
for (x = 0; x < w; x++) { |
612 |
5213952 |
blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, |
|
613 |
5213952 |
1 << hsub, hband, hsub + vsub, xm); |
|
614 |
5213952 |
dst += dst_delta; |
|
615 |
5213952 |
xm += 1 << hsub; |
|
616 |
} |
||
617 |
✗✓ | 606624 |
if (right) |
618 |
blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth, |
||
619 |
right, hband, hsub + vsub, xm); |
||
620 |
606624 |
} |
|
621 |
|||
622 |
18962 |
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, |
|
623 |
uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, |
||
624 |
const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, |
||
625 |
int l2depth, unsigned endianness, int x0, int y0) |
||
626 |
{ |
||
627 |
unsigned alpha, nb_planes, nb_comp, plane, comp; |
||
628 |
int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y; |
||
629 |
uint8_t *p0, *p; |
||
630 |
const uint8_t *m; |
||
631 |
|||
632 |
18962 |
clip_interval(dst_w, &x0, &mask_w, &xm0); |
|
633 |
18962 |
clip_interval(dst_h, &y0, &mask_h, &ym0); |
|
634 |
18962 |
mask += ym0 * mask_linesize; |
|
635 |
✓✗✓✗ ✗✓ |
18962 |
if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3]) |
636 |
return; |
||
637 |
✓✓ | 18962 |
if (draw->desc->comp[0].depth <= 8) { |
638 |
/* alpha is in the [ 0 ; 0x10203 ] range, |
||
639 |
alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */ |
||
640 |
15552 |
alpha = (0x10307 * color->rgba[3] + 0x3) >> 8; |
|
641 |
} else { |
||
642 |
3410 |
alpha = (0x101 * color->rgba[3] + 0x2) >> 8; |
|
643 |
} |
||
644 |
✓✓✓✗ |
18962 |
nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA)); |
645 |
18962 |
nb_planes += !nb_planes; |
|
646 |
✓✓ | 67168 |
for (plane = 0; plane < nb_planes; plane++) { |
647 |
48206 |
nb_comp = draw->pixelstep[plane]; |
|
648 |
48206 |
p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0); |
|
649 |
48206 |
w_sub = mask_w; |
|
650 |
48206 |
h_sub = mask_h; |
|
651 |
48206 |
x_sub = x0; |
|
652 |
48206 |
y_sub = y0; |
|
653 |
48206 |
subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right); |
|
654 |
48206 |
subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom); |
|
655 |
✓✓ | 117492 |
for (comp = 0; comp < nb_comp; comp++) { |
656 |
69286 |
const int depth = draw->desc->comp[comp].depth; |
|
657 |
|||
658 |
✓✓ | 69286 |
if (!component_used(draw, plane, comp)) |
659 |
12400 |
continue; |
|
660 |
56886 |
p = p0 + comp; |
|
661 |
56886 |
m = mask; |
|
662 |
✗✓ | 56886 |
if (top) { |
663 |
if (depth <= 8) { |
||
664 |
blend_line_hv(p, draw->pixelstep[plane], |
||
665 |
color->comp[plane].u8[comp], alpha, |
||
666 |
m, mask_linesize, l2depth, w_sub, |
||
667 |
draw->hsub[plane], draw->vsub[plane], |
||
668 |
xm0, left, right, top); |
||
669 |
} else { |
||
670 |
blend_line_hv16(p, draw->pixelstep[plane], |
||
671 |
color->comp[plane].u16[comp], alpha, |
||
672 |
m, mask_linesize, l2depth, w_sub, |
||
673 |
draw->hsub[plane], draw->vsub[plane], |
||
674 |
xm0, left, right, top); |
||
675 |
} |
||
676 |
p += dst_linesize[plane]; |
||
677 |
m += top * mask_linesize; |
||
678 |
} |
||
679 |
✓✓ | 56886 |
if (depth <= 8) { |
680 |
✓✓ | 653280 |
for (y = 0; y < h_sub; y++) { |
681 |
606624 |
blend_line_hv(p, draw->pixelstep[plane], |
|
682 |
606624 |
color->comp[plane].u8[comp], alpha, |
|
683 |
m, mask_linesize, l2depth, w_sub, |
||
684 |
606624 |
draw->hsub[plane], draw->vsub[plane], |
|
685 |
606624 |
xm0, left, right, 1 << draw->vsub[plane]); |
|
686 |
606624 |
p += dst_linesize[plane]; |
|
687 |
606624 |
m += mask_linesize << draw->vsub[plane]; |
|
688 |
} |
||
689 |
} else { |
||
690 |
✓✓ | 173910 |
for (y = 0; y < h_sub; y++) { |
691 |
163680 |
blend_line_hv16(p, draw->pixelstep[plane], |
|
692 |
163680 |
color->comp[plane].u16[comp], alpha, |
|
693 |
m, mask_linesize, l2depth, w_sub, |
||
694 |
163680 |
draw->hsub[plane], draw->vsub[plane], |
|
695 |
163680 |
xm0, left, right, 1 << draw->vsub[plane]); |
|
696 |
163680 |
p += dst_linesize[plane]; |
|
697 |
163680 |
m += mask_linesize << draw->vsub[plane]; |
|
698 |
} |
||
699 |
} |
||
700 |
✗✓ | 56886 |
if (bottom) { |
701 |
if (depth <= 8) { |
||
702 |
blend_line_hv(p, draw->pixelstep[plane], |
||
703 |
color->comp[plane].u8[comp], alpha, |
||
704 |
m, mask_linesize, l2depth, w_sub, |
||
705 |
draw->hsub[plane], draw->vsub[plane], |
||
706 |
xm0, left, right, bottom); |
||
707 |
} else { |
||
708 |
blend_line_hv16(p, draw->pixelstep[plane], |
||
709 |
color->comp[plane].u16[comp], alpha, |
||
710 |
m, mask_linesize, l2depth, w_sub, |
||
711 |
draw->hsub[plane], draw->vsub[plane], |
||
712 |
xm0, left, right, bottom); |
||
713 |
} |
||
714 |
} |
||
715 |
} |
||
716 |
} |
||
717 |
} |
||
718 |
|||
719 |
157110 |
int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir, |
|
720 |
int value) |
||
721 |
{ |
||
722 |
✓✓ | 157110 |
unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max; |
723 |
|||
724 |
✓✓ | 157110 |
if (!shift) |
725 |
97310 |
return value; |
|
726 |
✓✓ | 59800 |
if (round_dir >= 0) |
727 |
✓✓ | 49302 |
value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1); |
728 |
59800 |
return (value >> shift) << shift; |
|
729 |
} |
||
730 |
|||
731 |
131 |
AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags) |
|
732 |
{ |
||
733 |
enum AVPixelFormat i; |
||
734 |
FFDrawContext draw; |
||
735 |
131 |
AVFilterFormats *fmts = NULL; |
|
736 |
int ret; |
||
737 |
|||
738 |
✓✓ | 26069 |
for (i = 0; av_pix_fmt_desc_get(i); i++) |
739 |
✓✓✗✓ |
36156 |
if (ff_draw_init(&draw, i, flags) >= 0 && |
740 |
10218 |
(ret = ff_add_format(&fmts, i)) < 0) |
|
741 |
return NULL; |
||
742 |
131 |
return fmts; |
|
743 |
} |
Generated by: GCOVR (Version 4.2) |