1 /*
2 * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3 * Copyright (C) 2006 Mindfruit Bv.
4 * Author: Sjoerd Simons <sjoerd@luon.net>
5 * Author: Alex Ugarte <alexugarte@gmail.com>
6 * Copyright (C) 2009 Alex Ugarte <augarte@vicomtech.org>
7 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library 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 GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "blend.h"
30 #include "compositororc.h"
31
32 #include <string.h>
33
34 #include <gst/video/video.h>
35
36 GST_DEBUG_CATEGORY_STATIC (gst_compositor_blend_debug);
37 #define GST_CAT_DEFAULT gst_compositor_blend_debug
38
39 /* Below are the implementations of everything */
40
41 /* A32 is for AYUV, ARGB and BGRA */
42 #define BLEND_A32(name, method, LOOP) \
43 static void \
44 method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
45 gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
46 { \
47 guint s_alpha; \
48 gint src_stride, dest_stride; \
49 gint dest_width, dest_height; \
50 guint8 *src, *dest; \
51 gint src_width, src_height; \
52 \
53 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
54 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
55 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
56 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
57 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
58 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
59 dest_width = GST_VIDEO_FRAME_COMP_WIDTH (destframe, 0); \
60 dest_height = GST_VIDEO_FRAME_COMP_HEIGHT (destframe, 0); \
61 \
62 s_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
63 \
64 /* If it's completely transparent... we just return */ \
65 if (G_UNLIKELY (s_alpha == 0)) \
66 return; \
67 \
68 /* adjust src pointers for negative sizes */ \
69 if (xpos < 0) { \
70 src += -xpos * 4; \
71 src_width -= -xpos; \
72 xpos = 0; \
73 } \
74 if (ypos < 0) { \
75 src += -ypos * src_stride; \
76 src_height -= -ypos; \
77 ypos = 0; \
78 } \
79 /* adjust width/height if the src is bigger than dest */ \
80 if (xpos + src_width > dest_width) { \
81 src_width = dest_width - xpos; \
82 } \
83 if (ypos + src_height > dest_height) { \
84 src_height = dest_height - ypos; \
85 } \
86 \
87 if (src_height > 0 && src_width > 0) { \
88 dest = dest + 4 * xpos + (ypos * dest_stride); \
89 \
90 LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha, \
91 mode); \
92 } \
93 }
94
95 #define OVERLAY_A32_LOOP(name) \
96 static inline void \
97 _overlay_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
98 gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
99 GstCompositorBlendMode mode) \
100 { \
101 s_alpha = MIN (255, s_alpha); \
102 switch (mode) { \
103 case COMPOSITOR_BLEND_MODE_SOURCE:\
104 compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
105 s_alpha, src_width, src_height); \
106 break;\
107 case COMPOSITOR_BLEND_MODE_OVER:\
108 compositor_orc_overlay_##name (dest, dest_stride, src, src_stride, \
109 s_alpha, src_width, src_height); \
110 break;\
111 case COMPOSITOR_BLEND_MODE_ADD:\
112 compositor_orc_overlay_##name##_addition (dest, dest_stride, src, src_stride, \
113 s_alpha, src_width, src_height); \
114 break;\
115 }\
116 }
117
118 #define BLEND_A32_LOOP(name) \
119 static inline void \
120 _blend_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
121 gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
122 GstCompositorBlendMode mode) \
123 { \
124 s_alpha = MIN (255, s_alpha); \
125 switch (mode) { \
126 case COMPOSITOR_BLEND_MODE_SOURCE:\
127 compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
128 s_alpha, src_width, src_height); \
129 break;\
130 case COMPOSITOR_BLEND_MODE_OVER:\
131 case COMPOSITOR_BLEND_MODE_ADD:\
132 /* both modes are the same for opaque background */ \
133 compositor_orc_blend_##name (dest, dest_stride, src, src_stride, \
134 s_alpha, src_width, src_height); \
135 break;\
136 }\
137 }
138
139 OVERLAY_A32_LOOP (argb);
140 OVERLAY_A32_LOOP (bgra);
141 BLEND_A32_LOOP (argb);
142 BLEND_A32_LOOP (bgra);
143
144 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
145 BLEND_A32 (argb, blend, _blend_loop_argb);
146 BLEND_A32 (bgra, blend, _blend_loop_bgra);
147 BLEND_A32 (argb, overlay, _overlay_loop_argb);
148 BLEND_A32 (bgra, overlay, _overlay_loop_bgra);
149 #else
150 BLEND_A32 (argb, blend, _blend_loop_bgra);
151 BLEND_A32 (bgra, blend, _blend_loop_argb);
152 BLEND_A32 (argb, overlay, _overlay_loop_bgra);
153 BLEND_A32 (bgra, overlay, _overlay_loop_argb);
154 #endif
155
156 #define A32_CHECKER_C(name, RGB, A, C1, C2, C3) \
157 static void \
158 fill_checker_##name##_c (GstVideoFrame * frame) \
159 { \
160 gint i, j; \
161 gint val; \
162 static const gint tab[] = { 80, 160, 80, 160 }; \
163 gint width, height; \
164 guint8 *dest; \
165 \
166 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
167 width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
168 height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
169 \
170 if (!RGB) { \
171 for (i = 0; i < height; i++) { \
172 for (j = 0; j < width; j++) { \
173 dest[A] = 0xff; \
174 dest[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
175 dest[C2] = 128; \
176 dest[C3] = 128; \
177 dest += 4; \
178 } \
179 } \
180 } else { \
181 for (i = 0; i < height; i++) { \
182 for (j = 0; j < width; j++) { \
183 val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
184 dest[A] = 0xFF; \
185 dest[C1] = val; \
186 dest[C2] = val; \
187 dest[C3] = val; \
188 dest += 4; \
189 } \
190 } \
191 } \
192 }
193
194 A32_CHECKER_C (argb, TRUE, 0, 1, 2, 3);
195 A32_CHECKER_C (bgra, TRUE, 3, 2, 1, 0);
196 A32_CHECKER_C (ayuv, FALSE, 0, 1, 2, 3);
197
198 #define YUV_TO_R(Y,U,V) (CLAMP (1.164 * (Y - 16) + 1.596 * (V - 128), 0, 255))
199 #define YUV_TO_G(Y,U,V) (CLAMP (1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128), 0, 255))
200 #define YUV_TO_B(Y,U,V) (CLAMP (1.164 * (Y - 16) + 2.018 * (U - 128), 0, 255))
201
202 #define A32_COLOR(name, RGB, A, C1, C2, C3) \
203 static void \
204 fill_color_##name (GstVideoFrame * frame, gint Y, gint U, gint V) \
205 { \
206 gint c1, c2, c3; \
207 guint32 val; \
208 gint width, height; \
209 guint8 *dest; \
210 \
211 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
212 width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
213 height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
214 \
215 if (RGB) { \
216 c1 = YUV_TO_R (Y, U, V); \
217 c2 = YUV_TO_G (Y, U, V); \
218 c3 = YUV_TO_B (Y, U, V); \
219 } else { \
220 c1 = Y; \
221 c2 = U; \
222 c3 = V; \
223 } \
224 val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
225 \
226 compositor_orc_splat_u32 ((guint32 *) dest, val, height * width); \
227 }
228
229 A32_COLOR (argb, TRUE, 24, 16, 8, 0);
230 A32_COLOR (bgra, TRUE, 0, 8, 16, 24);
231 A32_COLOR (abgr, TRUE, 24, 0, 8, 16);
232 A32_COLOR (rgba, TRUE, 0, 24, 16, 8);
233 A32_COLOR (ayuv, FALSE, 24, 16, 8, 0);
234
235 /* Y444, Y42B, I420, YV12, Y41B */
236 #define PLANAR_YUV_BLEND(format_name,format_enum,x_round,y_round,MEMCPY,BLENDLOOP) \
237 inline static void \
238 _blend_##format_name (const guint8 * src, guint8 * dest, \
239 gint src_stride, gint dest_stride, gint src_width, gint src_height, \
240 gdouble src_alpha, GstCompositorBlendMode mode) \
241 { \
242 gint i; \
243 gint b_alpha; \
244 \
245 /* in source mode we just have to copy over things */ \
246 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
247 src_alpha = 1.0; \
248 } \
249 \
250 /* If it's completely transparent... we just return */ \
251 if (G_UNLIKELY (src_alpha == 0.0)) { \
252 GST_LOG ("Fast copy (alpha == 0.0)"); \
253 return; \
254 } \
255 \
256 /* If it's completely opaque, we do a fast copy */ \
257 if (G_UNLIKELY (src_alpha == 1.0)) { \
258 GST_LOG ("Fast copy (alpha == 1.0)"); \
259 for (i = 0; i < src_height; i++) { \
260 MEMCPY (dest, src, src_width); \
261 src += src_stride; \
262 dest += dest_stride; \
263 } \
264 return; \
265 } \
266 \
267 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
268 \
269 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height);\
270 } \
271 \
272 static void \
273 blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
274 gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
275 { \
276 const guint8 *b_src; \
277 guint8 *b_dest; \
278 gint b_src_width; \
279 gint b_src_height; \
280 gint xoffset = 0; \
281 gint yoffset = 0; \
282 gint src_comp_rowstride, dest_comp_rowstride; \
283 gint src_comp_height; \
284 gint src_comp_width; \
285 gint comp_ypos, comp_xpos; \
286 gint comp_yoffset, comp_xoffset; \
287 gint dest_width, dest_height; \
288 const GstVideoFormatInfo *info; \
289 gint src_width, src_height; \
290 \
291 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
292 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
293 \
294 info = srcframe->info.finfo; \
295 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
296 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
297 \
298 xpos = x_round (xpos); \
299 ypos = y_round (ypos); \
300 \
301 b_src_width = src_width; \
302 b_src_height = src_height; \
303 \
304 /* adjust src pointers for negative sizes */ \
305 if (xpos < 0) { \
306 xoffset = -xpos; \
307 b_src_width -= -xpos; \
308 xpos = 0; \
309 } \
310 if (ypos < 0) { \
311 yoffset = -ypos; \
312 b_src_height -= -ypos; \
313 ypos = 0; \
314 } \
315 /* If x or y offset are larger then the source it's outside of the picture */ \
316 if (xoffset >= src_width || yoffset >= src_height) { \
317 return; \
318 } \
319 \
320 /* adjust width/height if the src is bigger than dest */ \
321 if (xpos + b_src_width > dest_width) { \
322 b_src_width = dest_width - xpos; \
323 } \
324 if (ypos + b_src_height > dest_height) { \
325 b_src_height = dest_height - ypos; \
326 } \
327 if (b_src_width <= 0 || b_src_height <= 0) { \
328 return; \
329 } \
330 \
331 /* First mix Y, then U, then V */ \
332 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
333 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
334 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
335 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
336 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
337 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
338 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
339 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
340 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
341 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
342 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
343 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
344 src_comp_rowstride, \
345 dest_comp_rowstride, src_comp_width, src_comp_height, \
346 src_alpha, mode); \
347 \
348 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 1); \
349 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 1); \
350 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
351 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
352 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
353 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
354 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
355 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
356 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
357 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
358 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
359 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
360 src_comp_rowstride, \
361 dest_comp_rowstride, src_comp_width, src_comp_height, \
362 src_alpha, mode); \
363 \
364 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 2); \
365 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 2); \
366 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 2); \
367 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 2); \
368 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 2, b_src_width); \
369 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, b_src_height); \
370 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xpos); \
371 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, ypos); \
372 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xoffset); \
373 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, yoffset); \
374 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
375 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
376 src_comp_rowstride, \
377 dest_comp_rowstride, src_comp_width, src_comp_height, \
378 src_alpha, mode); \
379 }
380
381 #define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
382 static void \
383 fill_checker_##format_name (GstVideoFrame * frame) \
384 { \
385 gint i, j; \
386 static const int tab[] = { 80, 160, 80, 160 }; \
387 guint8 *p; \
388 gint comp_width, comp_height; \
389 gint rowstride; \
390 \
391 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
392 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
393 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
394 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
395 \
396 for (i = 0; i < comp_height; i++) { \
397 for (j = 0; j < comp_width; j++) { \
398 *p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
399 } \
400 p += rowstride - comp_width; \
401 } \
402 \
403 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
404 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
405 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
406 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
407 \
408 for (i = 0; i < comp_height; i++) { \
409 MEMSET (p, 0x80, comp_width); \
410 p += rowstride; \
411 } \
412 \
413 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
414 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
415 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
416 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
417 \
418 for (i = 0; i < comp_height; i++) { \
419 MEMSET (p, 0x80, comp_width); \
420 p += rowstride; \
421 } \
422 }
423
424 #define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
425 static void \
426 fill_color_##format_name (GstVideoFrame * frame, \
427 gint colY, gint colU, gint colV) \
428 { \
429 guint8 *p; \
430 gint comp_width, comp_height; \
431 gint rowstride; \
432 gint i; \
433 \
434 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
435 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
436 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
437 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
438 \
439 for (i = 0; i < comp_height; i++) { \
440 MEMSET (p, colY, comp_width); \
441 p += rowstride; \
442 } \
443 \
444 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
445 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
446 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
447 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
448 \
449 for (i = 0; i < comp_height; i++) { \
450 MEMSET (p, colU, comp_width); \
451 p += rowstride; \
452 } \
453 \
454 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
455 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
456 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
457 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
458 \
459 for (i = 0; i < comp_height; i++) { \
460 MEMSET (p, colV, comp_width); \
461 p += rowstride; \
462 } \
463 }
464
465 #define GST_ROUND_UP_1(x) (x)
466
467 PLANAR_YUV_BLEND (i420, GST_VIDEO_FORMAT_I420, GST_ROUND_UP_2,
468 GST_ROUND_UP_2, memcpy, compositor_orc_blend_u8);
469 PLANAR_YUV_FILL_CHECKER (i420, GST_VIDEO_FORMAT_I420, memset);
470 PLANAR_YUV_FILL_COLOR (i420, GST_VIDEO_FORMAT_I420, memset);
471 PLANAR_YUV_FILL_COLOR (yv12, GST_VIDEO_FORMAT_YV12, memset);
472 PLANAR_YUV_BLEND (y444, GST_VIDEO_FORMAT_Y444, GST_ROUND_UP_1,
473 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
474 PLANAR_YUV_FILL_CHECKER (y444, GST_VIDEO_FORMAT_Y444, memset);
475 PLANAR_YUV_FILL_COLOR (y444, GST_VIDEO_FORMAT_Y444, memset);
476 PLANAR_YUV_BLEND (y42b, GST_VIDEO_FORMAT_Y42B, GST_ROUND_UP_2,
477 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
478 PLANAR_YUV_FILL_CHECKER (y42b, GST_VIDEO_FORMAT_Y42B, memset);
479 PLANAR_YUV_FILL_COLOR (y42b, GST_VIDEO_FORMAT_Y42B, memset);
480 PLANAR_YUV_BLEND (y41b, GST_VIDEO_FORMAT_Y41B, GST_ROUND_UP_4,
481 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
482 PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
483 PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
484
485 /* NV12, NV21 */
486 #define NV_YUV_BLEND(format_name,MEMCPY,BLENDLOOP) \
487 inline static void \
488 _blend_##format_name (const guint8 * src, guint8 * dest, \
489 gint src_stride, gint dest_stride, gint src_width, gint src_height, \
490 gdouble src_alpha, GstCompositorBlendMode mode) \
491 { \
492 gint i; \
493 gint b_alpha; \
494 \
495 /* in source mode we just have to copy over things */ \
496 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
497 src_alpha = 1.0; \
498 } \
499 \
500 /* If it's completely transparent... we just return */ \
501 if (G_UNLIKELY (src_alpha == 0.0)) { \
502 GST_LOG ("Fast copy (alpha == 0.0)"); \
503 return; \
504 } \
505 \
506 /* If it's completely opaque, we do a fast copy */ \
507 if (G_UNLIKELY (src_alpha == 1.0)) { \
508 GST_LOG ("Fast copy (alpha == 1.0)"); \
509 for (i = 0; i < src_height; i++) { \
510 MEMCPY (dest, src, src_width); \
511 src += src_stride; \
512 dest += dest_stride; \
513 } \
514 return; \
515 } \
516 \
517 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
518 \
519 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
520 } \
521 \
522 static void \
523 blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
524 gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
525 { \
526 const guint8 *b_src; \
527 guint8 *b_dest; \
528 gint b_src_width; \
529 gint b_src_height; \
530 gint xoffset = 0; \
531 gint yoffset = 0; \
532 gint src_comp_rowstride, dest_comp_rowstride; \
533 gint src_comp_height; \
534 gint src_comp_width; \
535 gint comp_ypos, comp_xpos; \
536 gint comp_yoffset, comp_xoffset; \
537 gint dest_width, dest_height; \
538 const GstVideoFormatInfo *info; \
539 gint src_width, src_height; \
540 \
541 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
542 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
543 \
544 info = srcframe->info.finfo; \
545 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
546 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
547 \
548 xpos = GST_ROUND_UP_2 (xpos); \
549 ypos = GST_ROUND_UP_2 (ypos); \
550 \
551 b_src_width = src_width; \
552 b_src_height = src_height; \
553 \
554 /* adjust src pointers for negative sizes */ \
555 if (xpos < 0) { \
556 xoffset = -xpos; \
557 b_src_width -= -xpos; \
558 xpos = 0; \
559 } \
560 if (ypos < 0) { \
561 yoffset += -ypos; \
562 b_src_height -= -ypos; \
563 ypos = 0; \
564 } \
565 /* If x or y offset are larger then the source it's outside of the picture */ \
566 if (xoffset > src_width || yoffset > src_height) { \
567 return; \
568 } \
569 \
570 /* adjust width/height if the src is bigger than dest */ \
571 if (xpos + src_width > dest_width) { \
572 b_src_width = dest_width - xpos; \
573 } \
574 if (ypos + src_height > dest_height) { \
575 b_src_height = dest_height - ypos; \
576 } \
577 if (b_src_width < 0 || b_src_height < 0) { \
578 return; \
579 } \
580 \
581 /* First mix Y, then UV */ \
582 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
583 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
584 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
585 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
586 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
587 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
588 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
589 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
590 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
591 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
592 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
593 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
594 src_comp_rowstride, \
595 dest_comp_rowstride, src_comp_width, src_comp_height, \
596 src_alpha, mode); \
597 \
598 b_src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 1); \
599 b_dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 1); \
600 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
601 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
602 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
603 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
604 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
605 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
606 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
607 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
608 _blend_##format_name (b_src + comp_xoffset * 2 + comp_yoffset * src_comp_rowstride, \
609 b_dest + comp_xpos * 2 + comp_ypos * dest_comp_rowstride, \
610 src_comp_rowstride, \
611 dest_comp_rowstride, 2 * src_comp_width, src_comp_height, \
612 src_alpha, mode); \
613 }
614
615 #define NV_YUV_FILL_CHECKER(format_name, MEMSET) \
616 static void \
617 fill_checker_##format_name (GstVideoFrame * frame) \
618 { \
619 gint i, j; \
620 static const int tab[] = { 80, 160, 80, 160 }; \
621 guint8 *p; \
622 gint comp_width, comp_height; \
623 gint rowstride; \
624 \
625 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
626 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
627 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
628 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
629 \
630 for (i = 0; i < comp_height; i++) { \
631 for (j = 0; j < comp_width; j++) { \
632 *p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
633 } \
634 p += rowstride - comp_width; \
635 } \
636 \
637 p = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); \
638 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
639 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
640 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
641 \
642 for (i = 0; i < comp_height; i++) { \
643 MEMSET (p, 0x80, comp_width * 2); \
644 p += rowstride; \
645 } \
646 }
647
648 #define NV_YUV_FILL_COLOR(format_name,MEMSET) \
649 static void \
650 fill_color_##format_name (GstVideoFrame * frame, \
651 gint colY, gint colU, gint colV) \
652 { \
653 guint8 *y, *u, *v; \
654 gint comp_width, comp_height; \
655 gint rowstride; \
656 gint i, j; \
657 \
658 y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
659 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
660 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
661 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
662 \
663 for (i = 0; i < comp_height; i++) { \
664 MEMSET (y, colY, comp_width); \
665 y += rowstride; \
666 } \
667 \
668 u = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
669 v = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
670 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
671 comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
672 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
673 \
674 for (i = 0; i < comp_height; i++) { \
675 for (j = 0; j < comp_width; j++) { \
676 u[j*2] = colU; \
677 v[j*2] = colV; \
678 } \
679 u += rowstride; \
680 v += rowstride; \
681 } \
682 }
683
684 NV_YUV_BLEND (nv12, memcpy, compositor_orc_blend_u8);
685 NV_YUV_FILL_CHECKER (nv12, memset);
686 NV_YUV_FILL_COLOR (nv12, memset);
687 NV_YUV_BLEND (nv21, memcpy, compositor_orc_blend_u8);
688 NV_YUV_FILL_CHECKER (nv21, memset);
689
690 /* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
691
692 #define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
693 static void \
694 blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
695 gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
696 { \
697 gint b_alpha; \
698 gint i; \
699 gint src_stride, dest_stride; \
700 gint dest_width, dest_height; \
701 guint8 *dest, *src; \
702 gint src_width, src_height; \
703 \
704 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
705 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
706 \
707 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
708 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
709 \
710 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
711 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
712 \
713 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
714 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
715 \
716 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
717 \
718 /* adjust src pointers for negative sizes */ \
719 if (xpos < 0) { \
720 src += -xpos * bpp; \
721 src_width -= -xpos; \
722 xpos = 0; \
723 } \
724 if (ypos < 0) { \
725 src += -ypos * src_stride; \
726 src_height -= -ypos; \
727 ypos = 0; \
728 } \
729 /* adjust width/height if the src is bigger than dest */ \
730 if (xpos + src_width > dest_width) { \
731 src_width = dest_width - xpos; \
732 } \
733 if (ypos + src_height > dest_height) { \
734 src_height = dest_height - ypos; \
735 } \
736 \
737 dest = dest + bpp * xpos + (ypos * dest_stride); \
738 \
739 /* in source mode we just have to copy over things */ \
740 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
741 src_alpha = 1.0; \
742 } \
743 \
744 /* If it's completely transparent... we just return */ \
745 if (G_UNLIKELY (src_alpha == 0.0)) { \
746 GST_LOG ("Fast copy (alpha == 0.0)"); \
747 return; \
748 } \
749 \
750 /* If it's completely opaque, we do a fast copy */ \
751 if (G_UNLIKELY (src_alpha == 1.0)) { \
752 GST_LOG ("Fast copy (alpha == 1.0)"); \
753 for (i = 0; i < src_height; i++) { \
754 MEMCPY (dest, src, bpp * src_width); \
755 src += src_stride; \
756 dest += dest_stride; \
757 } \
758 return; \
759 } \
760 \
761 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
762 }
763
764 #define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
765 static void \
766 fill_checker_##name##_c (GstVideoFrame * frame) \
767 { \
768 gint i, j; \
769 static const int tab[] = { 80, 160, 80, 160 }; \
770 gint stride, dest_add, width, height; \
771 guint8 *dest; \
772 \
773 width = GST_VIDEO_FRAME_WIDTH (frame); \
774 height = GST_VIDEO_FRAME_HEIGHT (frame); \
775 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
776 stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
777 dest_add = stride - width * bpp; \
778 \
779 for (i = 0; i < height; i++) { \
780 for (j = 0; j < width; j++) { \
781 dest[r] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* red */ \
782 dest[g] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* green */ \
783 dest[b] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* blue */ \
784 dest += bpp; \
785 } \
786 dest += dest_add; \
787 } \
788 }
789
790 #define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
791 static void \
792 fill_color_##name (GstVideoFrame * frame, \
793 gint colY, gint colU, gint colV) \
794 { \
795 gint red, green, blue; \
796 gint i; \
797 gint dest_stride; \
798 gint width, height; \
799 guint8 *dest; \
800 \
801 width = GST_VIDEO_FRAME_WIDTH (frame); \
802 height = GST_VIDEO_FRAME_HEIGHT (frame); \
803 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
804 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
805 \
806 red = YUV_TO_R (colY, colU, colV); \
807 green = YUV_TO_G (colY, colU, colV); \
808 blue = YUV_TO_B (colY, colU, colV); \
809 \
810 for (i = 0; i < height; i++) { \
811 MEMSET_RGB (dest, red, green, blue, width); \
812 dest += dest_stride; \
813 } \
814 }
815
816 #define MEMSET_RGB_C(name, r, g, b) \
817 static inline void \
818 _memset_##name##_c (guint8* dest, gint red, gint green, gint blue, gint width) { \
819 gint j; \
820 \
821 for (j = 0; j < width; j++) { \
822 dest[r] = red; \
823 dest[g] = green; \
824 dest[b] = blue; \
825 dest += 3; \
826 } \
827 }
828
829 #define MEMSET_XRGB(name, r, g, b) \
830 static inline void \
831 _memset_##name (guint8* dest, gint red, gint green, gint blue, gint width) { \
832 guint32 val; \
833 \
834 val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
835 compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
836 }
837
838 #define _orc_memcpy_u32(dest,src,len) compositor_orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
839
840 RGB_BLEND (rgb, 3, memcpy, compositor_orc_blend_u8);
841 RGB_FILL_CHECKER_C (rgb, 3, 0, 1, 2);
842 MEMSET_RGB_C (rgb, 0, 1, 2);
843 RGB_FILL_COLOR (rgb_c, 3, _memset_rgb_c);
844
845 MEMSET_RGB_C (bgr, 2, 1, 0);
846 RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
847
848 RGB_BLEND (xrgb, 4, _orc_memcpy_u32, compositor_orc_blend_u8);
849 RGB_FILL_CHECKER_C (xrgb, 4, 1, 2, 3);
850 MEMSET_XRGB (xrgb, 24, 16, 0);
851 RGB_FILL_COLOR (xrgb, 4, _memset_xrgb);
852
853 MEMSET_XRGB (xbgr, 0, 16, 24);
854 RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
855
856 MEMSET_XRGB (rgbx, 24, 16, 8);
857 RGB_FILL_COLOR (rgbx, 4, _memset_rgbx);
858
859 MEMSET_XRGB (bgrx, 8, 16, 24);
860 RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
861
862 /* YUY2, YVYU, UYVY */
863
864 #define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
865 static void \
866 blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
867 gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
868 { \
869 gint b_alpha; \
870 gint i; \
871 gint src_stride, dest_stride; \
872 gint dest_width, dest_height; \
873 guint8 *src, *dest; \
874 gint src_width, src_height; \
875 \
876 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
877 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
878 \
879 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
880 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
881 \
882 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
883 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
884 \
885 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
886 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
887 \
888 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
889 \
890 xpos = GST_ROUND_UP_2 (xpos); \
891 \
892 /* adjust src pointers for negative sizes */ \
893 if (xpos < 0) { \
894 src += -xpos * 2; \
895 src_width -= -xpos; \
896 xpos = 0; \
897 } \
898 if (ypos < 0) { \
899 src += -ypos * src_stride; \
900 src_height -= -ypos; \
901 ypos = 0; \
902 } \
903 \
904 /* adjust width/height if the src is bigger than dest */ \
905 if (xpos + src_width > dest_width) { \
906 src_width = dest_width - xpos; \
907 } \
908 if (ypos + src_height > dest_height) { \
909 src_height = dest_height - ypos; \
910 } \
911 \
912 dest = dest + 2 * xpos + (ypos * dest_stride); \
913 \
914 /* in source mode we just have to copy over things */ \
915 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
916 src_alpha = 1.0; \
917 } \
918 \
919 /* If it's completely transparent... we just return */ \
920 if (G_UNLIKELY (src_alpha == 0.0)) { \
921 GST_LOG ("Fast copy (alpha == 0.0)"); \
922 return; \
923 } \
924 \
925 /* If it's completely opaque, we do a fast copy */ \
926 if (G_UNLIKELY (src_alpha == 1.0)) { \
927 GST_LOG ("Fast copy (alpha == 1.0)"); \
928 for (i = 0; i < src_height; i++) { \
929 MEMCPY (dest, src, 2 * src_width); \
930 src += src_stride; \
931 dest += dest_stride; \
932 } \
933 return; \
934 } \
935 \
936 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
937 }
938
939 #define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
940 static void \
941 fill_checker_##name##_c (GstVideoFrame * frame) \
942 { \
943 gint i, j; \
944 static const int tab[] = { 80, 160, 80, 160 }; \
945 gint dest_add; \
946 gint width, height; \
947 guint8 *dest; \
948 \
949 width = GST_VIDEO_FRAME_WIDTH (frame); \
950 width = GST_ROUND_UP_2 (width); \
951 height = GST_VIDEO_FRAME_HEIGHT (frame); \
952 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
953 dest_add = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) - width * 2; \
954 width /= 2; \
955 \
956 for (i = 0; i < height; i++) { \
957 for (j = 0; j < width; j++) { \
958 dest[Y1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
959 dest[Y2] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
960 dest[U] = 128; \
961 dest[V] = 128; \
962 dest += 4; \
963 } \
964 dest += dest_add; \
965 } \
966 }
967
968 #define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
969 static void \
970 fill_color_##name (GstVideoFrame * frame, \
971 gint colY, gint colU, gint colV) \
972 { \
973 gint i; \
974 gint dest_stride; \
975 guint32 val; \
976 gint width, height; \
977 guint8 *dest; \
978 \
979 width = GST_VIDEO_FRAME_WIDTH (frame); \
980 width = GST_ROUND_UP_2 (width); \
981 height = GST_VIDEO_FRAME_HEIGHT (frame); \
982 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
983 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
984 width /= 2; \
985 \
986 val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
987 \
988 for (i = 0; i < height; i++) { \
989 compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
990 dest += dest_stride; \
991 } \
992 }
993
994 PACKED_422_BLEND (yuy2, memcpy, compositor_orc_blend_u8);
995 PACKED_422_FILL_CHECKER_C (yuy2, 0, 1, 2, 3);
996 PACKED_422_FILL_CHECKER_C (uyvy, 1, 0, 3, 2);
997 PACKED_422_FILL_COLOR (yuy2, 24, 16, 8, 0);
998 PACKED_422_FILL_COLOR (yvyu, 24, 0, 8, 16);
999 PACKED_422_FILL_COLOR (uyvy, 16, 24, 0, 8);
1000
1001 /* Init function */
1002 BlendFunction gst_compositor_blend_argb;
1003 BlendFunction gst_compositor_blend_bgra;
1004 BlendFunction gst_compositor_overlay_argb;
1005 BlendFunction gst_compositor_overlay_bgra;
1006 /* AYUV/ABGR is equal to ARGB, RGBA is equal to BGRA */
1007 BlendFunction gst_compositor_blend_y444;
1008 BlendFunction gst_compositor_blend_y42b;
1009 BlendFunction gst_compositor_blend_i420;
1010 /* I420 is equal to YV12 */
1011 BlendFunction gst_compositor_blend_nv12;
1012 BlendFunction gst_compositor_blend_nv21;
1013 BlendFunction gst_compositor_blend_y41b;
1014 BlendFunction gst_compositor_blend_rgb;
1015 /* BGR is equal to RGB */
1016 BlendFunction gst_compositor_blend_rgbx;
1017 /* BGRx, xRGB, xBGR are equal to RGBx */
1018 BlendFunction gst_compositor_blend_yuy2;
1019 /* YVYU and UYVY are equal to YUY2 */
1020
1021 FillCheckerFunction gst_compositor_fill_checker_argb;
1022 FillCheckerFunction gst_compositor_fill_checker_bgra;
1023 /* ABGR is equal to ARGB, RGBA is equal to BGRA */
1024 FillCheckerFunction gst_compositor_fill_checker_ayuv;
1025 FillCheckerFunction gst_compositor_fill_checker_y444;
1026 FillCheckerFunction gst_compositor_fill_checker_y42b;
1027 FillCheckerFunction gst_compositor_fill_checker_i420;
1028 /* I420 is equal to YV12 */
1029 FillCheckerFunction gst_compositor_fill_checker_nv12;
1030 FillCheckerFunction gst_compositor_fill_checker_nv21;
1031 FillCheckerFunction gst_compositor_fill_checker_y41b;
1032 FillCheckerFunction gst_compositor_fill_checker_rgb;
1033 /* BGR is equal to RGB */
1034 FillCheckerFunction gst_compositor_fill_checker_xrgb;
1035 /* BGRx, xRGB, xBGR are equal to RGBx */
1036 FillCheckerFunction gst_compositor_fill_checker_yuy2;
1037 /* YVYU is equal to YUY2 */
1038 FillCheckerFunction gst_compositor_fill_checker_uyvy;
1039
1040 FillColorFunction gst_compositor_fill_color_argb;
1041 FillColorFunction gst_compositor_fill_color_bgra;
1042 FillColorFunction gst_compositor_fill_color_abgr;
1043 FillColorFunction gst_compositor_fill_color_rgba;
1044 FillColorFunction gst_compositor_fill_color_ayuv;
1045 FillColorFunction gst_compositor_fill_color_y444;
1046 FillColorFunction gst_compositor_fill_color_y42b;
1047 FillColorFunction gst_compositor_fill_color_i420;
1048 FillColorFunction gst_compositor_fill_color_yv12;
1049 FillColorFunction gst_compositor_fill_color_nv12;
1050 /* NV21 is equal to NV12 */
1051 FillColorFunction gst_compositor_fill_color_y41b;
1052 FillColorFunction gst_compositor_fill_color_rgb;
1053 FillColorFunction gst_compositor_fill_color_bgr;
1054 FillColorFunction gst_compositor_fill_color_xrgb;
1055 FillColorFunction gst_compositor_fill_color_xbgr;
1056 FillColorFunction gst_compositor_fill_color_rgbx;
1057 FillColorFunction gst_compositor_fill_color_bgrx;
1058 FillColorFunction gst_compositor_fill_color_yuy2;
1059 FillColorFunction gst_compositor_fill_color_yvyu;
1060 FillColorFunction gst_compositor_fill_color_uyvy;
1061
1062 void
gst_compositor_init_blend(void)1063 gst_compositor_init_blend (void)
1064 {
1065 GST_DEBUG_CATEGORY_INIT (gst_compositor_blend_debug, "compositor_blend", 0,
1066 "video compositor blending functions");
1067
1068 gst_compositor_blend_argb = GST_DEBUG_FUNCPTR (blend_argb);
1069 gst_compositor_blend_bgra = GST_DEBUG_FUNCPTR (blend_bgra);
1070 gst_compositor_overlay_argb = GST_DEBUG_FUNCPTR (overlay_argb);
1071 gst_compositor_overlay_bgra = GST_DEBUG_FUNCPTR (overlay_bgra);
1072 gst_compositor_blend_i420 = GST_DEBUG_FUNCPTR (blend_i420);
1073 gst_compositor_blend_nv12 = GST_DEBUG_FUNCPTR (blend_nv12);
1074 gst_compositor_blend_nv21 = GST_DEBUG_FUNCPTR (blend_nv21);
1075 gst_compositor_blend_y444 = GST_DEBUG_FUNCPTR (blend_y444);
1076 gst_compositor_blend_y42b = GST_DEBUG_FUNCPTR (blend_y42b);
1077 gst_compositor_blend_y41b = GST_DEBUG_FUNCPTR (blend_y41b);
1078 gst_compositor_blend_rgb = GST_DEBUG_FUNCPTR (blend_rgb);
1079 gst_compositor_blend_xrgb = GST_DEBUG_FUNCPTR (blend_xrgb);
1080 gst_compositor_blend_yuy2 = GST_DEBUG_FUNCPTR (blend_yuy2);
1081
1082 gst_compositor_fill_checker_argb = GST_DEBUG_FUNCPTR (fill_checker_argb_c);
1083 gst_compositor_fill_checker_bgra = GST_DEBUG_FUNCPTR (fill_checker_bgra_c);
1084 gst_compositor_fill_checker_ayuv = GST_DEBUG_FUNCPTR (fill_checker_ayuv_c);
1085 gst_compositor_fill_checker_i420 = GST_DEBUG_FUNCPTR (fill_checker_i420);
1086 gst_compositor_fill_checker_nv12 = GST_DEBUG_FUNCPTR (fill_checker_nv12);
1087 gst_compositor_fill_checker_nv21 = GST_DEBUG_FUNCPTR (fill_checker_nv21);
1088 gst_compositor_fill_checker_y444 = GST_DEBUG_FUNCPTR (fill_checker_y444);
1089 gst_compositor_fill_checker_y42b = GST_DEBUG_FUNCPTR (fill_checker_y42b);
1090 gst_compositor_fill_checker_y41b = GST_DEBUG_FUNCPTR (fill_checker_y41b);
1091 gst_compositor_fill_checker_rgb = GST_DEBUG_FUNCPTR (fill_checker_rgb_c);
1092 gst_compositor_fill_checker_xrgb = GST_DEBUG_FUNCPTR (fill_checker_xrgb_c);
1093 gst_compositor_fill_checker_yuy2 = GST_DEBUG_FUNCPTR (fill_checker_yuy2_c);
1094 gst_compositor_fill_checker_uyvy = GST_DEBUG_FUNCPTR (fill_checker_uyvy_c);
1095
1096 gst_compositor_fill_color_argb = GST_DEBUG_FUNCPTR (fill_color_argb);
1097 gst_compositor_fill_color_bgra = GST_DEBUG_FUNCPTR (fill_color_bgra);
1098 gst_compositor_fill_color_abgr = GST_DEBUG_FUNCPTR (fill_color_abgr);
1099 gst_compositor_fill_color_rgba = GST_DEBUG_FUNCPTR (fill_color_rgba);
1100 gst_compositor_fill_color_ayuv = GST_DEBUG_FUNCPTR (fill_color_ayuv);
1101 gst_compositor_fill_color_i420 = GST_DEBUG_FUNCPTR (fill_color_i420);
1102 gst_compositor_fill_color_yv12 = GST_DEBUG_FUNCPTR (fill_color_yv12);
1103 gst_compositor_fill_color_nv12 = GST_DEBUG_FUNCPTR (fill_color_nv12);
1104 gst_compositor_fill_color_y444 = GST_DEBUG_FUNCPTR (fill_color_y444);
1105 gst_compositor_fill_color_y42b = GST_DEBUG_FUNCPTR (fill_color_y42b);
1106 gst_compositor_fill_color_y41b = GST_DEBUG_FUNCPTR (fill_color_y41b);
1107 gst_compositor_fill_color_rgb = GST_DEBUG_FUNCPTR (fill_color_rgb_c);
1108 gst_compositor_fill_color_bgr = GST_DEBUG_FUNCPTR (fill_color_bgr_c);
1109 gst_compositor_fill_color_xrgb = GST_DEBUG_FUNCPTR (fill_color_xrgb);
1110 gst_compositor_fill_color_xbgr = GST_DEBUG_FUNCPTR (fill_color_xbgr);
1111 gst_compositor_fill_color_rgbx = GST_DEBUG_FUNCPTR (fill_color_rgbx);
1112 gst_compositor_fill_color_bgrx = GST_DEBUG_FUNCPTR (fill_color_bgrx);
1113 gst_compositor_fill_color_yuy2 = GST_DEBUG_FUNCPTR (fill_color_yuy2);
1114 gst_compositor_fill_color_yvyu = GST_DEBUG_FUNCPTR (fill_color_yvyu);
1115 gst_compositor_fill_color_uyvy = GST_DEBUG_FUNCPTR (fill_color_uyvy);
1116 }
1117