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>
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.
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.
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., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
34 #include <gst/video/video.h>
36 #define BLEND(D,S,alpha) (((D) * (256 - (alpha)) + (S) * (alpha)) >> 8)
38 GST_DEBUG_CATEGORY_STATIC (gst_videomixer_blend_debug);
39 #define GST_CAT_DEFAULT gst_videomixer_blend_debug
41 /* Below are the implementations of everything */
43 /* A32 is for AYUV, ARGB and BGRA */
44 #define BLEND_A32(name, method, LOOP) \
46 method##_ ##name (const guint8 * src, gint xpos, gint ypos, \
47 gint src_width, gint src_height, gdouble src_alpha, \
48 guint8 * dest, gint dest_width, gint dest_height) \
51 gint src_stride, dest_stride; \
53 src_stride = src_width * 4; \
54 dest_stride = dest_width * 4; \
56 s_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
58 /* If it's completely transparent... we just return */ \
59 if (G_UNLIKELY (s_alpha == 0)) \
62 /* adjust src pointers for negative sizes */ \
69 src += -ypos * src_stride; \
70 src_height -= -ypos; \
73 /* adjust width/height if the src is bigger than dest */ \
74 if (xpos + src_width > dest_width) { \
75 src_width = dest_width - xpos; \
77 if (ypos + src_height > dest_height) { \
78 src_height = dest_height - ypos; \
81 dest = dest + 4 * xpos + (ypos * dest_stride); \
83 LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha); \
86 #define BLEND_A32_LOOP(name, method) \
88 _##method##_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
89 gint src_width, gint src_stride, gint dest_stride, guint s_alpha) \
91 s_alpha = MIN (255, s_alpha); \
92 orc_##method##_##name (dest, dest_stride, src, src_stride, \
93 s_alpha, src_width, src_height); \
96 BLEND_A32_LOOP (argb, blend);
97 BLEND_A32_LOOP (bgra, blend);
98 BLEND_A32_LOOP (argb, overlay);
99 BLEND_A32_LOOP (bgra, overlay);
101 #if G_BYTE_ORDER == LITTLE_ENDIAN
102 BLEND_A32 (argb, blend, _blend_loop_argb);
103 BLEND_A32 (bgra, blend, _blend_loop_bgra);
104 BLEND_A32 (argb, overlay, _overlay_loop_argb);
105 BLEND_A32 (bgra, overlay, _overlay_loop_bgra);
107 BLEND_A32 (argb, blend, _blend_loop_bgra);
108 BLEND_A32 (bgra, blend, _blend_loop_argb);
109 BLEND_A32 (argb, overlay, _overlay_loop_bgra);
110 BLEND_A32 (bgra, overlay, _overlay_loop_argb);
113 #define A32_CHECKER_C(name, RGB, A, C1, C2, C3) \
115 fill_checker_##name##_c (guint8 * dest, gint width, gint height) \
119 static const gint tab[] = { 80, 160, 80, 160 }; \
122 for (i = 0; i < height; i++) { \
123 for (j = 0; j < width; j++) { \
125 dest[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
132 for (i = 0; i < height; i++) { \
133 for (j = 0; j < width; j++) { \
134 val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
145 A32_CHECKER_C (argb, TRUE, 0, 1, 2, 3);
146 A32_CHECKER_C (bgra, TRUE, 3, 2, 1, 0);
147 A32_CHECKER_C (ayuv, FALSE, 0, 1, 2, 3);
149 #define YUV_TO_R(Y,U,V) (CLAMP (1.164 * (Y - 16) + 1.596 * (V - 128), 0, 255))
150 #define YUV_TO_G(Y,U,V) (CLAMP (1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128), 0, 255))
151 #define YUV_TO_B(Y,U,V) (CLAMP (1.164 * (Y - 16) + 2.018 * (U - 128), 0, 255))
153 #define A32_COLOR(name, RGB, A, C1, C2, C3) \
155 fill_color_##name (guint8 * dest, gint width, gint height, gint Y, gint U, gint V) \
161 c1 = YUV_TO_R (Y, U, V); \
162 c2 = YUV_TO_G (Y, U, V); \
163 c3 = YUV_TO_B (Y, U, V); \
169 val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
171 orc_splat_u32 ((guint32 *) dest, val, height * width); \
174 A32_COLOR (argb, TRUE, 24, 16, 8, 0);
175 A32_COLOR (bgra, TRUE, 0, 8, 16, 24);
176 A32_COLOR (abgr, TRUE, 24, 0, 8, 16);
177 A32_COLOR (rgba, TRUE, 0, 24, 16, 8);
178 A32_COLOR (ayuv, FALSE, 24, 16, 8, 0);
180 /* Y444, Y42B, I420, YV12, Y41B */
181 #define PLANAR_YUV_BLEND(format_name,format_enum,x_round,y_round,MEMCPY,BLENDLOOP) \
183 _blend_##format_name (const guint8 * src, guint8 * dest, \
184 gint src_stride, gint dest_stride, gint src_width, gint src_height, \
190 /* If it's completely transparent... we just return */ \
191 if (G_UNLIKELY (src_alpha == 0.0)) { \
192 GST_INFO ("Fast copy (alpha == 0.0)"); \
196 /* If it's completely opaque, we do a fast copy */ \
197 if (G_UNLIKELY (src_alpha == 1.0)) { \
198 GST_INFO ("Fast copy (alpha == 1.0)"); \
199 for (i = 0; i < src_height; i++) { \
200 MEMCPY (dest, src, src_width); \
202 dest += dest_stride; \
207 b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
209 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
213 blend_##format_name (const guint8 * src, gint xpos, gint ypos, \
214 gint src_width, gint src_height, gdouble src_alpha, \
215 guint8 * dest, gint dest_width, gint dest_height) \
217 const guint8 *b_src; \
219 gint b_src_width = src_width; \
220 gint b_src_height = src_height; \
223 gint src_comp_rowstride, dest_comp_rowstride; \
224 gint src_comp_height; \
225 gint src_comp_width; \
226 gint comp_ypos, comp_xpos; \
227 gint comp_yoffset, comp_xoffset; \
229 xpos = x_round (xpos); \
230 ypos = y_round (ypos); \
232 /* adjust src pointers for negative sizes */ \
235 b_src_width -= -xpos; \
240 b_src_height -= -ypos; \
243 /* If x or y offset are larger then the source it's outside of the picture */ \
244 if (xoffset > src_width || yoffset > src_width) { \
248 /* adjust width/height if the src is bigger than dest */ \
249 if (xpos + src_width > dest_width) { \
250 b_src_width = dest_width - xpos; \
252 if (ypos + src_height > dest_height) { \
253 b_src_height = dest_height - ypos; \
255 if (b_src_width < 0 || b_src_height < 0) { \
259 /* First mix Y, then U, then V */ \
260 b_src = src + gst_video_format_get_component_offset (format_enum, 0, src_width, src_height); \
261 b_dest = dest + gst_video_format_get_component_offset (format_enum, 0, dest_width, dest_height); \
262 src_comp_rowstride = gst_video_format_get_row_stride (format_enum, 0, src_width); \
263 dest_comp_rowstride = gst_video_format_get_row_stride (format_enum, 0, dest_width); \
264 src_comp_height = gst_video_format_get_component_height (format_enum, 0, b_src_height); \
265 src_comp_width = gst_video_format_get_component_width (format_enum, 0, b_src_width); \
266 comp_xpos = (xpos == 0) ? 0 : gst_video_format_get_component_width (format_enum, 0, xpos); \
267 comp_ypos = (ypos == 0) ? 0 : gst_video_format_get_component_height (format_enum, 0, ypos); \
268 comp_xoffset = (xoffset == 0) ? 0 : gst_video_format_get_component_width (format_enum, 0, xoffset); \
269 comp_yoffset = (yoffset == 0) ? 0 : gst_video_format_get_component_height (format_enum, 0, yoffset); \
270 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
271 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
272 src_comp_rowstride, \
273 dest_comp_rowstride, src_comp_width, src_comp_height, \
276 b_src = src + gst_video_format_get_component_offset (format_enum, 1, src_width, src_height); \
277 b_dest = dest + gst_video_format_get_component_offset (format_enum, 1, dest_width, dest_height); \
278 src_comp_rowstride = gst_video_format_get_row_stride (format_enum, 1, src_width); \
279 dest_comp_rowstride = gst_video_format_get_row_stride (format_enum, 1, dest_width); \
280 src_comp_height = gst_video_format_get_component_height (format_enum, 1, b_src_height); \
281 src_comp_width = gst_video_format_get_component_width (format_enum, 1, b_src_width); \
282 comp_xpos = (xpos == 0) ? 0 : gst_video_format_get_component_width (format_enum, 1, xpos); \
283 comp_ypos = (ypos == 0) ? 0 : gst_video_format_get_component_height (format_enum, 1, ypos); \
284 comp_xoffset = (xoffset == 0) ? 0 : gst_video_format_get_component_width (format_enum, 1, xoffset); \
285 comp_yoffset = (yoffset == 0) ? 0 : gst_video_format_get_component_height (format_enum, 1, yoffset); \
286 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
287 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
288 src_comp_rowstride, \
289 dest_comp_rowstride, src_comp_width, src_comp_height, \
292 b_src = src + gst_video_format_get_component_offset (format_enum, 2, src_width, src_height); \
293 b_dest = dest + gst_video_format_get_component_offset (format_enum, 2, dest_width, dest_height); \
294 src_comp_rowstride = gst_video_format_get_row_stride (format_enum, 2, src_width); \
295 dest_comp_rowstride = gst_video_format_get_row_stride (format_enum, 2, dest_width); \
296 src_comp_height = gst_video_format_get_component_height (format_enum, 2, b_src_height); \
297 src_comp_width = gst_video_format_get_component_width (format_enum, 2, b_src_width); \
298 comp_xpos = (xpos == 0) ? 0 : gst_video_format_get_component_width (format_enum, 2, xpos); \
299 comp_ypos = (ypos == 0) ? 0 : gst_video_format_get_component_height (format_enum, 2, ypos); \
300 comp_xoffset = (xoffset == 0) ? 0 : gst_video_format_get_component_width (format_enum, 2, xoffset); \
301 comp_yoffset = (yoffset == 0) ? 0 : gst_video_format_get_component_height (format_enum, 2, yoffset); \
302 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
303 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
304 src_comp_rowstride, \
305 dest_comp_rowstride, src_comp_width, src_comp_height, \
309 #define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
311 fill_checker_##format_name (guint8 * dest, gint width, gint height) \
314 static const int tab[] = { 80, 160, 80, 160 }; \
316 gint comp_width, comp_height; \
319 p = dest + gst_video_format_get_component_offset (format_enum, 0, width, height); \
320 comp_width = gst_video_format_get_component_width (format_enum, 0, width); \
321 comp_height = gst_video_format_get_component_height (format_enum, 0, height); \
322 rowstride = gst_video_format_get_row_stride (format_enum, 0, width); \
324 for (i = 0; i < comp_height; i++) { \
325 for (j = 0; j < comp_width; j++) { \
326 *p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
328 p += rowstride - comp_width; \
331 p = dest + gst_video_format_get_component_offset (format_enum, 1, width, height); \
332 comp_width = gst_video_format_get_component_width (format_enum, 1, width); \
333 comp_height = gst_video_format_get_component_height (format_enum, 1, height); \
334 rowstride = gst_video_format_get_row_stride (format_enum, 1, width); \
336 for (i = 0; i < comp_height; i++) { \
337 MEMSET (p, 0x80, comp_width); \
341 p = dest + gst_video_format_get_component_offset (format_enum, 2, width, height); \
342 comp_width = gst_video_format_get_component_width (format_enum, 2, width); \
343 comp_height = gst_video_format_get_component_height (format_enum, 2, height); \
344 rowstride = gst_video_format_get_row_stride (format_enum, 2, width); \
346 for (i = 0; i < comp_height; i++) { \
347 MEMSET (p, 0x80, comp_width); \
352 #define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
354 fill_color_##format_name (guint8 * dest, gint width, gint height, \
355 gint colY, gint colU, gint colV) \
358 gint comp_width, comp_height; \
362 p = dest + gst_video_format_get_component_offset (format_enum, 0, width, height); \
363 comp_width = gst_video_format_get_component_width (format_enum, 0, width); \
364 comp_height = gst_video_format_get_component_height (format_enum, 0, height); \
365 rowstride = gst_video_format_get_row_stride (format_enum, 0, width); \
367 for (i = 0; i < comp_height; i++) { \
368 MEMSET (p, colY, comp_width); \
372 p = dest + gst_video_format_get_component_offset (format_enum, 1, width, height); \
373 comp_width = gst_video_format_get_component_width (format_enum, 1, width); \
374 comp_height = gst_video_format_get_component_height (format_enum, 1, height); \
375 rowstride = gst_video_format_get_row_stride (format_enum, 1, width); \
377 for (i = 0; i < comp_height; i++) { \
378 MEMSET (p, colU, comp_width); \
382 p = dest + gst_video_format_get_component_offset (format_enum, 2, width, height); \
383 comp_width = gst_video_format_get_component_width (format_enum, 2, width); \
384 comp_height = gst_video_format_get_component_height (format_enum, 2, height); \
385 rowstride = gst_video_format_get_row_stride (format_enum, 2, width); \
387 for (i = 0; i < comp_height; i++) { \
388 MEMSET (p, colV, comp_width); \
393 #define GST_ROUND_UP_1(x) (x)
395 PLANAR_YUV_BLEND (i420, GST_VIDEO_FORMAT_I420, GST_ROUND_UP_2,
396 GST_ROUND_UP_2, memcpy, orc_blend_u8);
397 PLANAR_YUV_FILL_CHECKER (i420, GST_VIDEO_FORMAT_I420, memset);
398 PLANAR_YUV_FILL_COLOR (i420, GST_VIDEO_FORMAT_I420, memset);
399 PLANAR_YUV_FILL_COLOR (yv12, GST_VIDEO_FORMAT_YV12, memset);
400 PLANAR_YUV_BLEND (y444, GST_VIDEO_FORMAT_Y444, GST_ROUND_UP_1,
401 GST_ROUND_UP_1, memcpy, orc_blend_u8);
402 PLANAR_YUV_FILL_CHECKER (y444, GST_VIDEO_FORMAT_Y444, memset);
403 PLANAR_YUV_FILL_COLOR (y444, GST_VIDEO_FORMAT_Y444, memset);
404 PLANAR_YUV_BLEND (y42b, GST_VIDEO_FORMAT_Y42B, GST_ROUND_UP_2,
405 GST_ROUND_UP_1, memcpy, orc_blend_u8);
406 PLANAR_YUV_FILL_CHECKER (y42b, GST_VIDEO_FORMAT_Y42B, memset);
407 PLANAR_YUV_FILL_COLOR (y42b, GST_VIDEO_FORMAT_Y42B, memset);
408 PLANAR_YUV_BLEND (y41b, GST_VIDEO_FORMAT_Y41B, GST_ROUND_UP_4,
409 GST_ROUND_UP_1, memcpy, orc_blend_u8);
410 PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
411 PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
413 /* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
415 #define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
417 blend_##name (const guint8 * src, gint xpos, gint ypos, \
418 gint src_width, gint src_height, gdouble src_alpha, \
419 guint8 * dest, gint dest_width, gint dest_height) \
423 gint src_stride, dest_stride; \
425 src_stride = GST_ROUND_UP_4 (src_width * bpp); \
426 dest_stride = GST_ROUND_UP_4 (dest_width * bpp); \
428 b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
430 /* adjust src pointers for negative sizes */ \
432 src += -xpos * bpp; \
433 src_width -= -xpos; \
437 src += -ypos * src_stride; \
438 src_height -= -ypos; \
441 /* adjust width/height if the src is bigger than dest */ \
442 if (xpos + src_width > dest_width) { \
443 src_width = dest_width - xpos; \
445 if (ypos + src_height > dest_height) { \
446 src_height = dest_height - ypos; \
449 dest = dest + bpp * xpos + (ypos * dest_stride); \
450 /* If it's completely transparent... we just return */ \
451 if (G_UNLIKELY (src_alpha == 0.0)) { \
452 GST_INFO ("Fast copy (alpha == 0.0)"); \
456 /* If it's completely opaque, we do a fast copy */ \
457 if (G_UNLIKELY (src_alpha == 1.0)) { \
458 GST_INFO ("Fast copy (alpha == 1.0)"); \
459 for (i = 0; i < src_height; i++) { \
460 MEMCPY (dest, src, bpp * src_width); \
462 dest += dest_stride; \
467 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
470 #define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
472 fill_checker_##name##_c (guint8 * dest, gint width, gint height) \
475 static const int tab[] = { 80, 160, 80, 160 }; \
476 gint dest_add = GST_ROUND_UP_4 (width * bpp) - width * bpp; \
478 for (i = 0; i < height; i++) { \
479 for (j = 0; j < width; j++) { \
480 dest[r] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* red */ \
481 dest[g] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* green */ \
482 dest[b] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* blue */ \
489 #define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
491 fill_color_##name (guint8 * dest, gint width, gint height, \
492 gint colY, gint colU, gint colV) \
494 gint red, green, blue; \
496 gint dest_stride = GST_ROUND_UP_4 (width * bpp); \
498 red = YUV_TO_R (colY, colU, colV); \
499 green = YUV_TO_G (colY, colU, colV); \
500 blue = YUV_TO_B (colY, colU, colV); \
502 for (i = 0; i < height; i++) { \
503 MEMSET_RGB (dest, red, green, blue, width); \
504 dest += dest_stride; \
508 #define MEMSET_RGB_C(name, r, g, b) \
510 _memset_##name##_c (guint8* dest, gint red, gint green, gint blue, gint width) { \
513 for (j = 0; j < width; j++) { \
521 #define MEMSET_XRGB(name, r, g, b) \
523 _memset_##name (guint8* dest, gint red, gint green, gint blue, gint width) { \
526 val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
527 orc_splat_u32 ((guint32 *) dest, val, width); \
530 #define _orc_memcpy_u32(dest,src,len) orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
532 RGB_BLEND (rgb, 3, memcpy, orc_blend_u8);
533 RGB_FILL_CHECKER_C (rgb, 3, 0, 1, 2);
534 MEMSET_RGB_C (rgb, 0, 1, 2);
535 RGB_FILL_COLOR (rgb_c, 3, _memset_rgb_c);
537 MEMSET_RGB_C (bgr, 2, 1, 0);
538 RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
540 RGB_BLEND (xrgb, 4, _orc_memcpy_u32, orc_blend_u8);
541 RGB_FILL_CHECKER_C (xrgb, 4, 1, 2, 3);
542 MEMSET_XRGB (xrgb, 24, 16, 0);
543 RGB_FILL_COLOR (xrgb, 4, _memset_xrgb);
545 MEMSET_XRGB (xbgr, 0, 16, 24);
546 RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
548 MEMSET_XRGB (rgbx, 24, 16, 8);
549 RGB_FILL_COLOR (rgbx, 4, _memset_rgbx);
551 MEMSET_XRGB (bgrx, 8, 16, 24);
552 RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
554 /* YUY2, YVYU, UYVY */
556 #define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
558 blend_##name (const guint8 * src, gint xpos, gint ypos, \
559 gint src_width, gint src_height, gdouble src_alpha, \
560 guint8 * dest, gint dest_width, gint dest_height) \
564 gint src_stride, dest_stride; \
566 src_stride = GST_ROUND_UP_4 (src_width * 2); \
567 dest_stride = GST_ROUND_UP_4 (dest_width * 2); \
569 b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
571 xpos = GST_ROUND_UP_2 (xpos); \
573 /* adjust src pointers for negative sizes */ \
576 src_width -= -xpos; \
580 src += -ypos * src_stride; \
581 src_height -= -ypos; \
585 /* adjust width/height if the src is bigger than dest */ \
586 if (xpos + src_width > dest_width) { \
587 src_width = dest_width - xpos; \
589 if (ypos + src_height > dest_height) { \
590 src_height = dest_height - ypos; \
593 dest = dest + 2 * xpos + (ypos * dest_stride); \
594 /* If it's completely transparent... we just return */ \
595 if (G_UNLIKELY (src_alpha == 0.0)) { \
596 GST_INFO ("Fast copy (alpha == 0.0)"); \
600 /* If it's completely opaque, we do a fast copy */ \
601 if (G_UNLIKELY (src_alpha == 1.0)) { \
602 GST_INFO ("Fast copy (alpha == 1.0)"); \
603 for (i = 0; i < src_height; i++) { \
604 MEMCPY (dest, src, 2 * src_width); \
606 dest += dest_stride; \
611 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
614 #define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
616 fill_checker_##name##_c (guint8 * dest, gint width, gint height) \
619 static const int tab[] = { 80, 160, 80, 160 }; \
622 width = GST_ROUND_UP_2 (width); \
623 dest_add = GST_ROUND_UP_4 (width * 2) - width * 2; \
626 for (i = 0; i < height; i++) { \
627 for (j = 0; j < width; j++) { \
628 dest[Y1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
629 dest[Y2] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
638 #define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
640 fill_color_##name (guint8 * dest, gint width, gint height, \
641 gint colY, gint colU, gint colV) \
647 width = GST_ROUND_UP_2 (width); \
648 dest_stride = GST_ROUND_UP_4 (width * 2); \
651 val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
653 for (i = 0; i < height; i++) { \
654 orc_splat_u32 ((guint32 *) dest, val, width); \
655 dest += dest_stride; \
659 PACKED_422_BLEND (yuy2, memcpy, orc_blend_u8);
660 PACKED_422_FILL_CHECKER_C (yuy2, 0, 1, 2, 3);
661 PACKED_422_FILL_CHECKER_C (uyvy, 1, 0, 3, 2);
662 PACKED_422_FILL_COLOR (yuy2, 24, 16, 8, 0);
663 PACKED_422_FILL_COLOR (yvyu, 24, 0, 8, 16);
664 PACKED_422_FILL_COLOR (uyvy, 16, 24, 0, 8);
667 BlendFunction gst_video_mixer_blend_argb;
668 BlendFunction gst_video_mixer_blend_bgra;
669 BlendFunction gst_video_mixer_overlay_argb;
670 BlendFunction gst_video_mixer_overlay_bgra;
671 /* AYUV/ABGR is equal to ARGB, RGBA is equal to BGRA */
672 BlendFunction gst_video_mixer_blend_y444;
673 BlendFunction gst_video_mixer_blend_y42b;
674 BlendFunction gst_video_mixer_blend_i420;
675 /* I420 is equal to YV12 */
676 BlendFunction gst_video_mixer_blend_y41b;
677 BlendFunction gst_video_mixer_blend_rgb;
678 /* BGR is equal to RGB */
679 BlendFunction gst_video_mixer_blend_rgbx;
680 /* BGRx, xRGB, xBGR are equal to RGBx */
681 BlendFunction gst_video_mixer_blend_yuy2;
682 /* YVYU and UYVY are equal to YUY2 */
684 FillCheckerFunction gst_video_mixer_fill_checker_argb;
685 FillCheckerFunction gst_video_mixer_fill_checker_bgra;
686 /* ABGR is equal to ARGB, RGBA is equal to BGRA */
687 FillCheckerFunction gst_video_mixer_fill_checker_ayuv;
688 FillCheckerFunction gst_video_mixer_fill_checker_y444;
689 FillCheckerFunction gst_video_mixer_fill_checker_y42b;
690 FillCheckerFunction gst_video_mixer_fill_checker_i420;
691 /* I420 is equal to YV12 */
692 FillCheckerFunction gst_video_mixer_fill_checker_y41b;
693 FillCheckerFunction gst_video_mixer_fill_checker_rgb;
694 /* BGR is equal to RGB */
695 FillCheckerFunction gst_video_mixer_fill_checker_xrgb;
696 /* BGRx, xRGB, xBGR are equal to RGBx */
697 FillCheckerFunction gst_video_mixer_fill_checker_yuy2;
698 /* YVYU is equal to YUY2 */
699 FillCheckerFunction gst_video_mixer_fill_checker_uyvy;
701 FillColorFunction gst_video_mixer_fill_color_argb;
702 FillColorFunction gst_video_mixer_fill_color_bgra;
703 FillColorFunction gst_video_mixer_fill_color_abgr;
704 FillColorFunction gst_video_mixer_fill_color_rgba;
705 FillColorFunction gst_video_mixer_fill_color_ayuv;
706 FillColorFunction gst_video_mixer_fill_color_y444;
707 FillColorFunction gst_video_mixer_fill_color_y42b;
708 FillColorFunction gst_video_mixer_fill_color_i420;
709 FillColorFunction gst_video_mixer_fill_color_yv12;
710 FillColorFunction gst_video_mixer_fill_color_y41b;
711 FillColorFunction gst_video_mixer_fill_color_rgb;
712 FillColorFunction gst_video_mixer_fill_color_bgr;
713 FillColorFunction gst_video_mixer_fill_color_xrgb;
714 FillColorFunction gst_video_mixer_fill_color_xbgr;
715 FillColorFunction gst_video_mixer_fill_color_rgbx;
716 FillColorFunction gst_video_mixer_fill_color_bgrx;
717 FillColorFunction gst_video_mixer_fill_color_yuy2;
718 FillColorFunction gst_video_mixer_fill_color_yvyu;
719 FillColorFunction gst_video_mixer_fill_color_uyvy;
722 gst_video_mixer_init_blend (void)
724 GST_DEBUG_CATEGORY_INIT (gst_videomixer_blend_debug, "videomixer_blend", 0,
725 "video mixer blending functions");
727 gst_video_mixer_blend_argb = blend_argb;
728 gst_video_mixer_blend_bgra = blend_bgra;
729 gst_video_mixer_overlay_argb = overlay_argb;
730 gst_video_mixer_overlay_bgra = overlay_bgra;
731 gst_video_mixer_blend_i420 = blend_i420;
732 gst_video_mixer_blend_y444 = blend_y444;
733 gst_video_mixer_blend_y42b = blend_y42b;
734 gst_video_mixer_blend_y41b = blend_y41b;
735 gst_video_mixer_blend_rgb = blend_rgb;
736 gst_video_mixer_blend_xrgb = blend_xrgb;
737 gst_video_mixer_blend_yuy2 = blend_yuy2;
739 gst_video_mixer_fill_checker_argb = fill_checker_argb_c;
740 gst_video_mixer_fill_checker_bgra = fill_checker_bgra_c;
741 gst_video_mixer_fill_checker_ayuv = fill_checker_ayuv_c;
742 gst_video_mixer_fill_checker_i420 = fill_checker_i420;
743 gst_video_mixer_fill_checker_y444 = fill_checker_y444;
744 gst_video_mixer_fill_checker_y42b = fill_checker_y42b;
745 gst_video_mixer_fill_checker_y41b = fill_checker_y41b;
746 gst_video_mixer_fill_checker_rgb = fill_checker_rgb_c;
747 gst_video_mixer_fill_checker_xrgb = fill_checker_xrgb_c;
748 gst_video_mixer_fill_checker_yuy2 = fill_checker_yuy2_c;
749 gst_video_mixer_fill_checker_uyvy = fill_checker_uyvy_c;
751 gst_video_mixer_fill_color_argb = fill_color_argb;
752 gst_video_mixer_fill_color_bgra = fill_color_bgra;
753 gst_video_mixer_fill_color_abgr = fill_color_abgr;
754 gst_video_mixer_fill_color_rgba = fill_color_rgba;
755 gst_video_mixer_fill_color_ayuv = fill_color_ayuv;
756 gst_video_mixer_fill_color_i420 = fill_color_i420;
757 gst_video_mixer_fill_color_yv12 = fill_color_yv12;
758 gst_video_mixer_fill_color_y444 = fill_color_y444;
759 gst_video_mixer_fill_color_y42b = fill_color_y42b;
760 gst_video_mixer_fill_color_y41b = fill_color_y41b;
761 gst_video_mixer_fill_color_rgb = fill_color_rgb_c;
762 gst_video_mixer_fill_color_bgr = fill_color_bgr_c;
763 gst_video_mixer_fill_color_xrgb = fill_color_xrgb;
764 gst_video_mixer_fill_color_xbgr = fill_color_xbgr;
765 gst_video_mixer_fill_color_rgbx = fill_color_rgbx;
766 gst_video_mixer_fill_color_bgrx = fill_color_bgrx;
767 gst_video_mixer_fill_color_yuy2 = fill_color_yuy2;
768 gst_video_mixer_fill_color_yvyu = fill_color_yvyu;
769 gst_video_mixer_fill_color_uyvy = fill_color_uyvy;