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., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
30 #include "compositororc.h"
34 #include <gst/video/video.h>
36 GST_DEBUG_CATEGORY_STATIC (gst_compositor_blend_debug);
37 #define GST_CAT_DEFAULT gst_compositor_blend_debug
39 /* Below are the implementations of everything */
41 /* A32 is for AYUV, VUYA, ARGB and BGRA */
42 #define BLEND_A32(name, method, LOOP) \
44 method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
45 gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
46 gint dst_y_end, GstCompositorBlendMode mode) \
49 gint src_stride, dest_stride; \
50 gint dest_width, dest_height; \
52 gint src_width, src_height; \
54 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
55 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
56 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
57 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
58 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
59 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
60 dest_width = GST_VIDEO_FRAME_COMP_WIDTH (destframe, 0); \
61 dest_height = GST_VIDEO_FRAME_COMP_HEIGHT (destframe, 0); \
63 s_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
65 /* If it's completely transparent... we just return */ \
66 if (G_UNLIKELY (s_alpha == 0)) \
69 if (dst_y_end > dest_height) { \
70 dst_y_end = dest_height; \
72 /* adjust src pointers for negative sizes */ \
78 if (ypos < dst_y_start) { \
79 src += (dst_y_start - ypos) * src_stride; \
80 src_height -= dst_y_start - ypos; \
83 /* adjust width/height if the src is bigger than dest */ \
84 if (xpos + src_width > dest_width) { \
85 src_width = dest_width - xpos; \
87 if (ypos + src_height > dst_y_end) { \
88 src_height = dst_y_end - ypos; \
91 if (src_height > 0 && src_width > 0) { \
92 dest = dest + 4 * xpos + (ypos * dest_stride); \
94 LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha, \
99 #define OVERLAY_A32_LOOP(name) \
101 _overlay_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
102 gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
103 GstCompositorBlendMode mode) \
105 s_alpha = MIN (255, s_alpha); \
107 case COMPOSITOR_BLEND_MODE_SOURCE:\
108 if (s_alpha == 255) { \
110 for (y = 0; y < src_height; y++) { \
111 memcpy (dest, src, 4 * src_width); \
112 dest += dest_stride; \
116 compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
117 s_alpha, src_width, src_height); \
120 case COMPOSITOR_BLEND_MODE_OVER:\
121 compositor_orc_overlay_##name (dest, dest_stride, src, src_stride, \
122 s_alpha, src_width, src_height); \
124 case COMPOSITOR_BLEND_MODE_ADD:\
125 compositor_orc_overlay_##name##_addition (dest, dest_stride, src, src_stride, \
126 s_alpha, src_width, src_height); \
131 #define BLEND_A32_LOOP(name) \
133 _blend_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
134 gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
135 GstCompositorBlendMode mode) \
137 s_alpha = MIN (255, s_alpha); \
139 case COMPOSITOR_BLEND_MODE_SOURCE:\
140 if (s_alpha == 255) { \
142 for (y = 0; y < src_height; y++) { \
143 memcpy (dest, src, 4 * src_width); \
144 dest += dest_stride; \
148 compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
149 s_alpha, src_width, src_height); \
152 case COMPOSITOR_BLEND_MODE_OVER:\
153 case COMPOSITOR_BLEND_MODE_ADD:\
154 /* both modes are the same for opaque background */ \
155 compositor_orc_blend_##name (dest, dest_stride, src, src_stride, \
156 s_alpha, src_width, src_height); \
161 OVERLAY_A32_LOOP (argb);
162 OVERLAY_A32_LOOP (bgra);
163 BLEND_A32_LOOP (argb);
164 BLEND_A32_LOOP (bgra);
166 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
167 BLEND_A32 (argb, blend, _blend_loop_argb);
168 BLEND_A32 (bgra, blend, _blend_loop_bgra);
169 BLEND_A32 (argb, overlay, _overlay_loop_argb);
170 BLEND_A32 (bgra, overlay, _overlay_loop_bgra);
172 BLEND_A32 (argb, blend, _blend_loop_bgra);
173 BLEND_A32 (bgra, blend, _blend_loop_argb);
174 BLEND_A32 (argb, overlay, _overlay_loop_bgra);
175 BLEND_A32 (bgra, overlay, _overlay_loop_argb);
178 #define A32_CHECKER_C(name, RGB, A, C1, C2, C3) \
180 fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
184 static const gint tab[] = { 80, 160, 80, 160 }; \
185 gint width, stride; \
188 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
189 width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
190 stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
192 dest += y_start * stride; \
194 for (i = y_start; i < y_end; i++) { \
195 for (j = 0; j < width; j++) { \
197 dest[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
204 for (i = y_start; i < y_end; i++) { \
205 for (j = 0; j < width; j++) { \
206 val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
217 A32_CHECKER_C (argb, TRUE, 0, 1, 2, 3);
218 A32_CHECKER_C (bgra, TRUE, 3, 2, 1, 0);
219 A32_CHECKER_C (ayuv, FALSE, 0, 1, 2, 3);
220 A32_CHECKER_C (vuya, FALSE, 3, 2, 1, 0);
222 #define A32_COLOR(name, A, C1, C2, C3) \
224 fill_color_##name (GstVideoFrame * frame, guint y_start, guint y_end, gint c1, gint c2, gint c3) \
230 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
231 stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
233 dest += y_start * stride; \
234 val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
236 compositor_orc_splat_u32 ((guint32 *) dest, val, (y_end - y_start) * (stride / 4)); \
239 A32_COLOR (argb, 24, 16, 8, 0);
240 A32_COLOR (bgra, 0, 8, 16, 24);
241 A32_COLOR (abgr, 24, 0, 8, 16);
242 A32_COLOR (rgba, 0, 24, 16, 8);
243 A32_COLOR (ayuv, 24, 16, 8, 0);
244 A32_COLOR (vuya, 0, 8, 16, 24);
246 /* Y444, Y42B, I420, YV12, Y41B */
247 #define PLANAR_YUV_BLEND(format_name,x_round,y_round,MEMCPY,BLENDLOOP,n_bits) \
249 _blend_##format_name (const guint8 * src, guint8 * dest, \
250 gint src_stride, gint dest_stride, gint pstride, gint src_width, gint src_height, \
251 gdouble src_alpha, GstCompositorBlendMode mode) \
257 /* in source mode we just have to copy over things */ \
258 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
262 /* If it's completely transparent... we just return */ \
263 if (G_UNLIKELY (src_alpha == 0.0)) { \
264 GST_LOG ("Fast copy (alpha == 0.0)"); \
268 /* If it's completely opaque, we do a fast copy */ \
269 if (G_UNLIKELY (src_alpha == 1.0)) { \
270 gint width_in_bytes = src_width * pstride; \
271 GST_LOG ("Fast copy (alpha == 1.0)"); \
272 for (i = 0; i < src_height; i++) { \
273 MEMCPY (dest, src, width_in_bytes); \
275 dest += dest_stride; \
280 range = (1 << n_bits) - 1; \
281 b_alpha = CLAMP ((gint) (src_alpha * range), 0, range); \
283 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height);\
287 blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
288 gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
289 gint dst_y_end, GstCompositorBlendMode mode) \
291 const guint8 *b_src; \
297 gint src_comp_rowstride, dest_comp_rowstride; \
298 gint src_comp_height; \
299 gint src_comp_width; \
300 gint comp_ypos, comp_xpos; \
301 gint comp_yoffset, comp_xoffset; \
302 gint dest_width, dest_height; \
303 const GstVideoFormatInfo *info; \
304 gint src_width, src_height; \
307 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
308 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
310 info = srcframe->info.finfo; \
311 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
312 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
314 if (dst_y_end > dest_height) { \
315 dst_y_end = dest_height; \
317 xpos = x_round (xpos); \
318 ypos = y_round (ypos); \
320 b_src_width = src_width; \
321 b_src_height = src_height; \
323 /* adjust src pointers for negative sizes */ \
326 b_src_width -= -xpos; \
329 if (ypos < dst_y_start) { \
330 yoffset = dst_y_start - ypos; \
331 b_src_height -= dst_y_start - ypos; \
332 ypos = dst_y_start; \
334 /* If x or y offset are larger then the source it's outside of the picture */ \
335 if (xoffset >= src_width || yoffset >= src_height) { \
339 /* adjust width/height if the src is bigger than dest */ \
340 if (xpos + b_src_width > dest_width) { \
341 b_src_width = dest_width - xpos; \
343 if (ypos + b_src_height > dst_y_end) { \
344 b_src_height = dst_y_end - ypos; \
346 if (b_src_width <= 0 || b_src_height <= 0) { \
350 /* First mix Y, then U, then V */ \
351 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
352 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
353 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
354 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
355 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
356 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
357 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 0); \
358 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
359 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
360 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
361 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
362 _blend_##format_name (b_src + comp_xoffset * pstride + comp_yoffset * src_comp_rowstride, \
363 b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
364 src_comp_rowstride, \
365 dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
368 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 1); \
369 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 1); \
370 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
371 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
372 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
373 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
374 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 1); \
375 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
376 comp_ypos = (ypos == 0) ? 0 : ypos >> info->h_sub[1]; \
377 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
378 comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[1]; \
379 _blend_##format_name (b_src + comp_xoffset * pstride + comp_yoffset * src_comp_rowstride, \
380 b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
381 src_comp_rowstride, \
382 dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
385 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 2); \
386 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 2); \
387 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 2); \
388 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 2); \
389 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 2, b_src_width); \
390 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, b_src_height); \
391 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 2); \
392 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xpos); \
393 comp_ypos = (ypos == 0) ? 0 : ypos >> info->h_sub[2]; \
394 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xoffset); \
395 comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[2]; \
396 _blend_##format_name (b_src + comp_xoffset * pstride + comp_yoffset * src_comp_rowstride, \
397 b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
398 src_comp_rowstride, \
399 dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
403 #define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
405 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
408 static const int tab[] = { 80, 160, 80, 160 }; \
410 gint comp_width, comp_height; \
411 gint rowstride, comp_yoffset; \
412 const GstVideoFormatInfo *info; \
414 info = frame->info.finfo; \
415 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
416 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
417 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
418 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
419 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
420 p += comp_yoffset * rowstride; \
422 for (i = 0; i < comp_height; i++) { \
423 for (j = 0; j < comp_width; j++) { \
424 *p++ = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
426 p += rowstride - comp_width; \
429 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
430 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
431 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
432 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
433 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
434 p += comp_yoffset * rowstride; \
436 for (i = 0; i < comp_height; i++) { \
437 MEMSET (p, 0x80, comp_width); \
441 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
442 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
443 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
444 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
445 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
446 p += comp_yoffset * rowstride; \
448 for (i = 0; i < comp_height; i++) { \
449 MEMSET (p, 0x80, comp_width); \
454 #define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
456 fill_color_##format_name (GstVideoFrame * frame, \
457 guint y_start, guint y_end, gint colY, gint colU, gint colV) \
460 gint comp_width, comp_height; \
461 gint rowstride, comp_yoffset; \
463 const GstVideoFormatInfo *info; \
465 info = frame->info.finfo; \
466 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
467 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
468 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
469 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
470 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
471 p += comp_yoffset * rowstride; \
473 for (i = 0; i < comp_height; i++) { \
474 MEMSET (p, colY, comp_width); \
478 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
479 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
480 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
481 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
482 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
483 p += comp_yoffset * rowstride; \
485 for (i = 0; i < comp_height; i++) { \
486 MEMSET (p, colU, comp_width); \
490 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
491 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
492 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
493 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
494 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
495 p += comp_yoffset * rowstride; \
497 for (i = 0; i < comp_height; i++) { \
498 MEMSET (p, colV, comp_width); \
503 #define PLANAR_YUV_HIGH_FILL_CHECKER(format_name, nbits, endian, MEMSET) \
505 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
508 static const int tab[] = { 80 << (nbits - 8), 160 << (nbits - 8), 80 << (nbits - 8), 160 << (nbits - 8),}; \
510 gint comp_width, comp_height; \
511 gint rowstride, comp_yoffset; \
514 const GstVideoFormatInfo *info; \
516 info = frame->info.finfo; \
517 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
518 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
519 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
520 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
521 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); \
522 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
523 p += comp_yoffset * rowstride; \
525 for (i = 0; i < comp_height; i++) { \
526 for (j = 0; j < comp_width; j++) { \
527 GST_WRITE_UINT16_##endian (p, tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]); \
530 p += rowstride - comp_width * pstride; \
533 uv = GUINT16_TO_##endian (1 << (nbits - 1)); \
534 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
535 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
536 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
537 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
538 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1); \
539 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
540 p += comp_yoffset * rowstride; \
541 MEMSET (p, rowstride, uv, comp_width, comp_height); \
543 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
544 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
545 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
546 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
547 pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1); \
548 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
549 p += comp_yoffset * rowstride; \
550 MEMSET (p, rowstride, uv, comp_width, comp_height); \
553 #define PLANAR_YUV_HIGH_FILL_COLOR(format_name,endian,MEMSET) \
555 fill_color_##format_name (GstVideoFrame * frame, \
556 guint y_start, guint y_end, gint colY, gint colU, gint colV) \
559 gint comp_width, comp_height; \
560 gint rowstride, comp_yoffset; \
561 const GstVideoFormatInfo *info; \
563 info = frame->info.finfo; \
564 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
565 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
566 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
567 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
568 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
569 p += comp_yoffset * rowstride; \
570 MEMSET (p, rowstride, GUINT16_TO_##endian (colY), comp_width, comp_height); \
572 p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
573 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
574 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
575 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
576 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
577 p += comp_yoffset * rowstride; \
578 MEMSET (p, rowstride, GUINT16_TO_##endian (colU), comp_width, comp_height); \
580 p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
581 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
582 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
583 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
584 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
585 p += comp_yoffset * rowstride; \
586 MEMSET (p, rowstride, GUINT16_TO_##endian (colV), comp_width, comp_height); \
589 #define GST_ROUND_UP_1(x) (x)
591 PLANAR_YUV_BLEND (i420, GST_ROUND_UP_2,
592 GST_ROUND_UP_2, memcpy, compositor_orc_blend_u8, 8);
593 PLANAR_YUV_FILL_CHECKER (i420, GST_VIDEO_FORMAT_I420, memset);
594 PLANAR_YUV_FILL_COLOR (i420, GST_VIDEO_FORMAT_I420, memset);
595 PLANAR_YUV_FILL_COLOR (yv12, GST_VIDEO_FORMAT_YV12, memset);
596 PLANAR_YUV_BLEND (y444, GST_ROUND_UP_1,
597 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
598 PLANAR_YUV_FILL_CHECKER (y444, GST_VIDEO_FORMAT_Y444, memset);
599 PLANAR_YUV_FILL_COLOR (y444, GST_VIDEO_FORMAT_Y444, memset);
600 PLANAR_YUV_BLEND (y42b, GST_ROUND_UP_2,
601 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
602 PLANAR_YUV_FILL_CHECKER (y42b, GST_VIDEO_FORMAT_Y42B, memset);
603 PLANAR_YUV_FILL_COLOR (y42b, GST_VIDEO_FORMAT_Y42B, memset);
604 PLANAR_YUV_BLEND (y41b, GST_ROUND_UP_4,
605 GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
606 PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
607 PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
609 #define BLEND_HIGH(format_name) \
610 compositor_orc_blend_##format_name
612 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
613 PLANAR_YUV_BLEND (i420_10le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
614 BLEND_HIGH (u10), 10);
615 PLANAR_YUV_BLEND (i420_10be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
616 BLEND_HIGH (u10_swap), 10);
618 PLANAR_YUV_BLEND (i420_12le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
619 BLEND_HIGH (u12), 12);
620 PLANAR_YUV_BLEND (i420_12be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
621 BLEND_HIGH (u12_swap), 12);
623 PLANAR_YUV_BLEND (i422_10le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
624 BLEND_HIGH (u10), 10);
625 PLANAR_YUV_BLEND (i422_10be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
626 BLEND_HIGH (u10_swap), 10);
628 PLANAR_YUV_BLEND (i422_12le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
629 BLEND_HIGH (u12), 12);
630 PLANAR_YUV_BLEND (i422_12be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
631 BLEND_HIGH (u12_swap), 12);
632 #else /* G_BYTE_ORDER == G_LITTLE_ENDIAN */
633 PLANAR_YUV_BLEND (i420_10le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
634 BLEND_HIGH (u10_swap), 10);
635 PLANAR_YUV_BLEND (i420_10be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
636 BLEND_HIGH (u10), 10);
638 PLANAR_YUV_BLEND (i420_12le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
639 BLEND_HIGH (u12_swap), 12);
640 PLANAR_YUV_BLEND (i420_12be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
641 BLEND_HIGH (u12), 12);
643 PLANAR_YUV_BLEND (i422_10le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
644 BLEND_HIGH (u10_swap), 10);
645 PLANAR_YUV_BLEND (i422_10be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
646 BLEND_HIGH (u10), 10);
648 PLANAR_YUV_BLEND (i422_12le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
649 BLEND_HIGH (u12_swap), 12);
650 PLANAR_YUV_BLEND (i422_12be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
651 BLEND_HIGH (u12), 12);
652 #endif /* G_BYTE_ORDER == G_LITTLE_ENDIAN */
654 PLANAR_YUV_HIGH_FILL_CHECKER (i420_10le, 10, LE, compositor_orc_memset_u16_2d);
655 PLANAR_YUV_HIGH_FILL_COLOR (i420_10le, LE, compositor_orc_memset_u16_2d);
656 PLANAR_YUV_HIGH_FILL_CHECKER (i420_10be, 10, BE, compositor_orc_memset_u16_2d);
657 PLANAR_YUV_HIGH_FILL_COLOR (i420_10be, BE, compositor_orc_memset_u16_2d);
659 PLANAR_YUV_HIGH_FILL_CHECKER (i420_12le, 12, LE, compositor_orc_memset_u16_2d);
660 PLANAR_YUV_HIGH_FILL_COLOR (i420_12le, LE, compositor_orc_memset_u16_2d);
661 PLANAR_YUV_HIGH_FILL_CHECKER (i420_12be, 12, BE, compositor_orc_memset_u16_2d);
662 PLANAR_YUV_HIGH_FILL_COLOR (i420_12be, BE, compositor_orc_memset_u16_2d);
665 #define NV_YUV_BLEND(format_name,MEMCPY,BLENDLOOP) \
667 _blend_##format_name (const guint8 * src, guint8 * dest, \
668 gint src_stride, gint dest_stride, gint src_width, gint src_height, \
669 gdouble src_alpha, GstCompositorBlendMode mode) \
674 /* in source mode we just have to copy over things */ \
675 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
679 /* If it's completely transparent... we just return */ \
680 if (G_UNLIKELY (src_alpha == 0.0)) { \
681 GST_LOG ("Fast copy (alpha == 0.0)"); \
685 /* If it's completely opaque, we do a fast copy */ \
686 if (G_UNLIKELY (src_alpha == 1.0)) { \
687 GST_LOG ("Fast copy (alpha == 1.0)"); \
688 for (i = 0; i < src_height; i++) { \
689 MEMCPY (dest, src, src_width); \
691 dest += dest_stride; \
696 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
698 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
702 blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
703 gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
704 gint dst_y_end, GstCompositorBlendMode mode) \
706 const guint8 *b_src; \
712 gint src_comp_rowstride, dest_comp_rowstride; \
713 gint src_comp_height; \
714 gint src_comp_width; \
715 gint comp_ypos, comp_xpos; \
716 gint comp_yoffset, comp_xoffset; \
717 gint dest_width, dest_height; \
718 const GstVideoFormatInfo *info; \
719 gint src_width, src_height; \
721 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
722 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
724 info = srcframe->info.finfo; \
725 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
726 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
728 if (dst_y_end > dest_height) { \
729 dst_y_end = dest_height; \
731 xpos = GST_ROUND_UP_2 (xpos); \
732 ypos = GST_ROUND_UP_2 (ypos); \
734 b_src_width = src_width; \
735 b_src_height = src_height; \
737 /* adjust src pointers for negative sizes */ \
740 b_src_width -= -xpos; \
743 if (ypos < dst_y_start) { \
744 yoffset += dst_y_start - ypos; \
745 b_src_height -= dst_y_start - ypos; \
746 ypos = dst_y_start; \
748 /* If x or y offset are larger then the source it's outside of the picture */ \
749 if (xoffset > src_width || yoffset > src_height) { \
753 /* adjust width/height if the src is bigger than dest */ \
754 if (xpos + b_src_width > dest_width) { \
755 b_src_width = dest_width - xpos; \
757 if (ypos + b_src_height > dst_y_end) { \
758 b_src_height = dst_y_end - ypos; \
760 if (b_src_width < 0 || b_src_height < 0) { \
764 /* First mix Y, then UV */ \
765 b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
766 b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
767 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
768 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
769 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
770 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
771 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
772 comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
773 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
774 comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
775 _blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
776 b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
777 src_comp_rowstride, \
778 dest_comp_rowstride, src_comp_width, src_comp_height, \
781 b_src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 1); \
782 b_dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 1); \
783 src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
784 dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
785 src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
786 src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
787 comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
788 comp_ypos = (ypos == 0) ? 0 : ypos >> info->h_sub[1]; \
789 comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
790 comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[1]; \
791 _blend_##format_name (b_src + comp_xoffset * 2 + comp_yoffset * src_comp_rowstride, \
792 b_dest + comp_xpos * 2 + comp_ypos * dest_comp_rowstride, \
793 src_comp_rowstride, \
794 dest_comp_rowstride, 2 * src_comp_width, src_comp_height, \
798 #define NV_YUV_FILL_CHECKER(format_name, MEMSET) \
800 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
803 static const int tab[] = { 80, 160, 80, 160 }; \
805 gint comp_width, comp_height; \
806 gint rowstride, comp_yoffset; \
807 const GstVideoFormatInfo *info; \
809 info = frame->info.finfo; \
810 p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
811 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
812 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
813 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
814 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
815 p += comp_yoffset * rowstride; \
817 for (i = 0; i < comp_height; i++) { \
818 for (j = 0; j < comp_width; j++) { \
819 *p++ = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
821 p += rowstride - comp_width; \
824 p = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); \
825 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
826 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
827 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
828 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
829 p += comp_yoffset * rowstride; \
831 for (i = 0; i < comp_height; i++) { \
832 MEMSET (p, 0x80, comp_width * 2); \
837 #define NV_YUV_FILL_COLOR(format_name,MEMSET) \
839 fill_color_##format_name (GstVideoFrame * frame, \
840 guint y_start, guint y_end, gint colY, gint colU, gint colV) \
843 gint comp_width, comp_height; \
844 gint rowstride, comp_yoffset; \
846 const GstVideoFormatInfo *info; \
848 info = frame->info.finfo; \
849 y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
850 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
851 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
852 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
853 comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
855 y += comp_yoffset * rowstride; \
856 for (i = 0; i < comp_height; i++) { \
857 MEMSET (y, colY, comp_width); \
861 u = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
862 v = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
863 comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
864 comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
865 rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
866 comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
868 u += comp_yoffset * rowstride; \
869 v += comp_yoffset * rowstride; \
870 for (i = 0; i < comp_height; i++) { \
871 for (j = 0; j < comp_width; j++) { \
880 NV_YUV_BLEND (nv12, memcpy, compositor_orc_blend_u8);
881 NV_YUV_FILL_CHECKER (nv12, memset);
882 NV_YUV_FILL_COLOR (nv12, memset);
883 NV_YUV_BLEND (nv21, memcpy, compositor_orc_blend_u8);
884 NV_YUV_FILL_CHECKER (nv21, memset);
886 /* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
888 #define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
890 blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
891 gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
892 gint dst_y_end, GstCompositorBlendMode mode) \
896 gint src_stride, dest_stride; \
897 gint dest_width, dest_height; \
898 guint8 *dest, *src; \
899 gint src_width, src_height; \
901 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
902 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
904 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
905 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
907 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
908 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
910 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
911 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
913 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
915 if (dst_y_end > dest_height) { \
916 dst_y_end = dest_height; \
918 /* adjust src pointers for negative sizes */ \
920 src += -xpos * bpp; \
921 src_width -= -xpos; \
924 if (ypos < dst_y_start) { \
925 src += (dst_y_start - ypos) * src_stride; \
926 src_height -= dst_y_start - ypos; \
927 ypos = dst_y_start; \
929 /* adjust width/height if the src is bigger than dest */ \
930 if (xpos + src_width > dest_width) { \
931 src_width = dest_width - xpos; \
933 if (ypos + src_height > dst_y_end) { \
934 src_height = dst_y_end - ypos; \
937 dest = dest + bpp * xpos + (ypos * dest_stride); \
939 /* in source mode we just have to copy over things */ \
940 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
944 /* If it's completely transparent... we just return */ \
945 if (G_UNLIKELY (src_alpha == 0.0)) { \
946 GST_LOG ("Fast copy (alpha == 0.0)"); \
950 /* If it's completely opaque, we do a fast copy */ \
951 if (G_UNLIKELY (src_alpha == 1.0)) { \
952 GST_LOG ("Fast copy (alpha == 1.0)"); \
953 for (i = 0; i < src_height; i++) { \
954 MEMCPY (dest, src, bpp * src_width); \
956 dest += dest_stride; \
961 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
964 #define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
966 fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
969 static const int tab[] = { 80, 160, 80, 160 }; \
970 gint stride, dest_add, width, height; \
973 width = GST_VIDEO_FRAME_WIDTH (frame); \
974 height = y_end - y_start; \
975 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
976 stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
977 dest_add = stride - width * bpp; \
979 dest += y_start * stride; \
980 for (i = 0; i < height; i++) { \
981 for (j = 0; j < width; j++) { \
982 dest[r] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* red */ \
983 dest[g] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* green */ \
984 dest[b] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* blue */ \
991 #define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
993 fill_color_##name (GstVideoFrame * frame, \
994 guint y_start, guint y_end, gint colR, gint colG, gint colB) \
998 gint width, height; \
1001 width = GST_VIDEO_FRAME_WIDTH (frame); \
1002 height = y_end - y_start; \
1003 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
1004 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
1006 dest += y_start * dest_stride; \
1007 for (i = 0; i < height; i++) { \
1008 MEMSET_RGB (dest, colR, colG, colB, width); \
1009 dest += dest_stride; \
1013 #define MEMSET_RGB_C(name, r, g, b) \
1014 static inline void \
1015 _memset_##name##_c (guint8* dest, gint red, gint green, gint blue, gint width) { \
1018 for (j = 0; j < width; j++) { \
1026 #define MEMSET_XRGB(name, r, g, b) \
1027 static inline void \
1028 _memset_##name (guint8* dest, gint red, gint green, gint blue, gint width) { \
1031 val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
1032 compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
1035 #define _orc_memcpy_u32(dest,src,len) compositor_orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
1037 RGB_BLEND (rgb, 3, memcpy, compositor_orc_blend_u8);
1038 RGB_FILL_CHECKER_C (rgb, 3, 0, 1, 2);
1039 MEMSET_RGB_C (rgb, 0, 1, 2);
1040 RGB_FILL_COLOR (rgb_c, 3, _memset_rgb_c);
1042 MEMSET_RGB_C (bgr, 2, 1, 0);
1043 RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
1045 RGB_BLEND (xrgb, 4, _orc_memcpy_u32, compositor_orc_blend_u8);
1046 RGB_FILL_CHECKER_C (xrgb, 4, 1, 2, 3);
1047 MEMSET_XRGB (xrgb, 24, 16, 0);
1048 RGB_FILL_COLOR (xrgb, 4, _memset_xrgb);
1050 MEMSET_XRGB (xbgr, 0, 16, 24);
1051 RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
1053 RGB_FILL_CHECKER_C (rgbx, 4, 0, 1, 2);
1054 MEMSET_XRGB (rgbx, 24, 16, 8);
1055 RGB_FILL_COLOR (rgbx, 4, _memset_rgbx);
1057 MEMSET_XRGB (bgrx, 8, 16, 24);
1058 RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
1060 /* YUY2, YVYU, UYVY */
1062 #define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
1064 blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
1065 gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
1066 gint dst_y_end, GstCompositorBlendMode mode) \
1070 gint src_stride, dest_stride; \
1071 gint dest_width, dest_height; \
1072 guint8 *src, *dest; \
1073 gint src_width, src_height; \
1075 src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
1076 src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
1078 dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
1079 dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
1081 src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
1082 dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
1084 src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
1085 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
1087 b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
1089 xpos = GST_ROUND_UP_2 (xpos); \
1091 if (dst_y_end > dest_height) { \
1092 dst_y_end = dest_height; \
1094 /* adjust src pointers for negative sizes */ \
1097 src_width -= -xpos; \
1100 if (ypos < dst_y_start) { \
1101 src += (dst_y_start - ypos) * src_stride; \
1102 src_height -= dst_y_start - ypos; \
1103 ypos = dst_y_start; \
1106 /* adjust width/height if the src is bigger than dest */ \
1107 if (xpos + src_width > dest_width) { \
1108 src_width = dest_width - xpos; \
1110 if (ypos + src_height > dst_y_end) { \
1111 src_height = dst_y_end - ypos; \
1114 dest = dest + 2 * xpos + (ypos * dest_stride); \
1116 /* in source mode we just have to copy over things */ \
1117 if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
1121 /* If it's completely transparent... we just return */ \
1122 if (G_UNLIKELY (src_alpha == 0.0)) { \
1123 GST_LOG ("Fast copy (alpha == 0.0)"); \
1127 /* If it's completely opaque, we do a fast copy */ \
1128 if (G_UNLIKELY (src_alpha == 1.0)) { \
1129 GST_LOG ("Fast copy (alpha == 1.0)"); \
1130 for (i = 0; i < src_height; i++) { \
1131 MEMCPY (dest, src, 2 * src_width); \
1132 src += src_stride; \
1133 dest += dest_stride; \
1138 BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
1141 #define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
1143 fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
1146 static const int tab[] = { 80, 160, 80, 160 }; \
1148 gint width, height; \
1151 width = GST_VIDEO_FRAME_WIDTH (frame); \
1152 width = GST_ROUND_UP_2 (width); \
1153 height = y_end - y_start; \
1154 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
1155 dest_add = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) - width * 2; \
1158 dest += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * y_start; \
1159 for (i = 0; i < height; i++) { \
1160 for (j = 0; j < width; j++) { \
1161 dest[Y1] = tab[(((i + y_start) & 0x8) >> 3) + (((2 * j + 0) & 0x8) >> 3)]; \
1162 dest[Y2] = tab[(((i + y_start) & 0x8) >> 3) + (((2 * j + 1) & 0x8) >> 3)]; \
1171 #define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
1173 fill_color_##name (GstVideoFrame * frame, \
1174 guint y_start, guint y_end, gint colY, gint colU, gint colV) \
1179 gint width, height; \
1182 width = GST_VIDEO_FRAME_WIDTH (frame); \
1183 width = GST_ROUND_UP_2 (width); \
1184 height = y_end - y_start; \
1185 dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
1186 dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
1189 val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
1191 dest += dest_stride * y_start; \
1192 for (i = 0; i < height; i++) { \
1193 compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
1194 dest += dest_stride; \
1198 PACKED_422_BLEND (yuy2, memcpy, compositor_orc_blend_u8);
1199 PACKED_422_FILL_CHECKER_C (yuy2, 0, 1, 2, 3);
1200 PACKED_422_FILL_CHECKER_C (uyvy, 1, 0, 3, 2);
1201 PACKED_422_FILL_COLOR (yuy2, 24, 16, 8, 0);
1202 PACKED_422_FILL_COLOR (yvyu, 24, 0, 8, 16);
1203 PACKED_422_FILL_COLOR (uyvy, 16, 24, 0, 8);
1206 BlendFunction gst_compositor_blend_argb;
1207 BlendFunction gst_compositor_blend_bgra;
1208 BlendFunction gst_compositor_overlay_argb;
1209 BlendFunction gst_compositor_overlay_bgra;
1210 /* AYUV/ABGR is equal to ARGB, RGBA is equal to BGRA */
1211 BlendFunction gst_compositor_blend_y444;
1212 BlendFunction gst_compositor_blend_y42b;
1213 BlendFunction gst_compositor_blend_i420;
1214 /* I420 is equal to YV12 */
1215 BlendFunction gst_compositor_blend_nv12;
1216 BlendFunction gst_compositor_blend_nv21;
1217 BlendFunction gst_compositor_blend_y41b;
1218 BlendFunction gst_compositor_blend_rgb;
1219 /* BGR is equal to RGB */
1220 BlendFunction gst_compositor_blend_rgbx;
1221 /* BGRx, xRGB, xBGR are equal to RGBx */
1222 BlendFunction gst_compositor_blend_yuy2;
1223 /* YVYU and UYVY are equal to YUY2 */
1224 BlendFunction gst_compositor_blend_i420_10le;
1225 BlendFunction gst_compositor_blend_i420_10be;
1226 BlendFunction gst_compositor_blend_i420_12le;
1227 BlendFunction gst_compositor_blend_i420_12be;
1228 BlendFunction gst_compositor_blend_i422_10le;
1229 BlendFunction gst_compositor_blend_i422_10be;
1230 BlendFunction gst_compositor_blend_i422_12le;
1231 BlendFunction gst_compositor_blend_i422_12be;
1233 FillCheckerFunction gst_compositor_fill_checker_argb;
1234 FillCheckerFunction gst_compositor_fill_checker_bgra;
1235 /* ABGR is equal to ARGB, RGBA is equal to BGRA */
1236 FillCheckerFunction gst_compositor_fill_checker_ayuv;
1237 FillCheckerFunction gst_compositor_fill_checker_vuya;
1238 FillCheckerFunction gst_compositor_fill_checker_y444;
1239 FillCheckerFunction gst_compositor_fill_checker_y42b;
1240 FillCheckerFunction gst_compositor_fill_checker_i420;
1241 /* I420 is equal to YV12 */
1242 FillCheckerFunction gst_compositor_fill_checker_nv12;
1243 FillCheckerFunction gst_compositor_fill_checker_nv21;
1244 FillCheckerFunction gst_compositor_fill_checker_y41b;
1245 FillCheckerFunction gst_compositor_fill_checker_rgb;
1246 /* BGR is equal to RGB */
1247 FillCheckerFunction gst_compositor_fill_checker_xrgb;
1248 FillCheckerFunction gst_compositor_fill_checker_rgbx;
1249 /* BGRx, xRGB, xBGR are equal to RGBx */
1250 FillCheckerFunction gst_compositor_fill_checker_yuy2;
1251 /* YVYU is equal to YUY2 */
1252 FillCheckerFunction gst_compositor_fill_checker_uyvy;
1253 FillCheckerFunction gst_compositor_fill_checker_i420_10le;
1254 FillCheckerFunction gst_compositor_fill_checker_i420_10be;
1255 FillCheckerFunction gst_compositor_fill_checker_i420_12le;
1256 FillCheckerFunction gst_compositor_fill_checker_i420_12be;
1258 FillColorFunction gst_compositor_fill_color_argb;
1259 FillColorFunction gst_compositor_fill_color_bgra;
1260 FillColorFunction gst_compositor_fill_color_abgr;
1261 FillColorFunction gst_compositor_fill_color_rgba;
1262 FillColorFunction gst_compositor_fill_color_ayuv;
1263 FillColorFunction gst_compositor_fill_color_vuya;
1264 FillColorFunction gst_compositor_fill_color_y444;
1265 FillColorFunction gst_compositor_fill_color_y42b;
1266 FillColorFunction gst_compositor_fill_color_i420;
1267 FillColorFunction gst_compositor_fill_color_yv12;
1268 FillColorFunction gst_compositor_fill_color_nv12;
1269 /* NV21 is equal to NV12 */
1270 FillColorFunction gst_compositor_fill_color_y41b;
1271 FillColorFunction gst_compositor_fill_color_rgb;
1272 FillColorFunction gst_compositor_fill_color_bgr;
1273 FillColorFunction gst_compositor_fill_color_xrgb;
1274 FillColorFunction gst_compositor_fill_color_xbgr;
1275 FillColorFunction gst_compositor_fill_color_rgbx;
1276 FillColorFunction gst_compositor_fill_color_bgrx;
1277 FillColorFunction gst_compositor_fill_color_yuy2;
1278 FillColorFunction gst_compositor_fill_color_yvyu;
1279 FillColorFunction gst_compositor_fill_color_uyvy;
1280 FillColorFunction gst_compositor_fill_color_i420_10le;
1281 FillColorFunction gst_compositor_fill_color_i420_10be;
1282 FillColorFunction gst_compositor_fill_color_i420_12le;
1283 FillColorFunction gst_compositor_fill_color_i420_12be;
1286 gst_compositor_init_blend (void)
1288 GST_DEBUG_CATEGORY_INIT (gst_compositor_blend_debug, "compositor_blend", 0,
1289 "video compositor blending functions");
1291 gst_compositor_blend_argb = GST_DEBUG_FUNCPTR (blend_argb);
1292 gst_compositor_blend_bgra = GST_DEBUG_FUNCPTR (blend_bgra);
1293 gst_compositor_overlay_argb = GST_DEBUG_FUNCPTR (overlay_argb);
1294 gst_compositor_overlay_bgra = GST_DEBUG_FUNCPTR (overlay_bgra);
1295 gst_compositor_blend_i420 = GST_DEBUG_FUNCPTR (blend_i420);
1296 gst_compositor_blend_nv12 = GST_DEBUG_FUNCPTR (blend_nv12);
1297 gst_compositor_blend_nv21 = GST_DEBUG_FUNCPTR (blend_nv21);
1298 gst_compositor_blend_y444 = GST_DEBUG_FUNCPTR (blend_y444);
1299 gst_compositor_blend_y42b = GST_DEBUG_FUNCPTR (blend_y42b);
1300 gst_compositor_blend_y41b = GST_DEBUG_FUNCPTR (blend_y41b);
1301 gst_compositor_blend_rgb = GST_DEBUG_FUNCPTR (blend_rgb);
1302 gst_compositor_blend_xrgb = GST_DEBUG_FUNCPTR (blend_xrgb);
1303 gst_compositor_blend_yuy2 = GST_DEBUG_FUNCPTR (blend_yuy2);
1304 gst_compositor_blend_i420_10le = GST_DEBUG_FUNCPTR (blend_i420_10le);
1305 gst_compositor_blend_i420_10be = GST_DEBUG_FUNCPTR (blend_i420_10be);
1306 gst_compositor_blend_i420_12le = GST_DEBUG_FUNCPTR (blend_i420_12le);
1307 gst_compositor_blend_i420_12be = GST_DEBUG_FUNCPTR (blend_i420_12be);
1308 gst_compositor_blend_i422_10le = GST_DEBUG_FUNCPTR (blend_i422_10le);
1309 gst_compositor_blend_i422_10be = GST_DEBUG_FUNCPTR (blend_i422_10be);
1310 gst_compositor_blend_i422_12le = GST_DEBUG_FUNCPTR (blend_i422_12le);
1311 gst_compositor_blend_i422_12be = GST_DEBUG_FUNCPTR (blend_i422_12be);
1313 gst_compositor_fill_checker_argb = GST_DEBUG_FUNCPTR (fill_checker_argb_c);
1314 gst_compositor_fill_checker_bgra = GST_DEBUG_FUNCPTR (fill_checker_bgra_c);
1315 gst_compositor_fill_checker_ayuv = GST_DEBUG_FUNCPTR (fill_checker_ayuv_c);
1316 gst_compositor_fill_checker_vuya = GST_DEBUG_FUNCPTR (fill_checker_vuya_c);
1317 gst_compositor_fill_checker_i420 = GST_DEBUG_FUNCPTR (fill_checker_i420);
1318 gst_compositor_fill_checker_nv12 = GST_DEBUG_FUNCPTR (fill_checker_nv12);
1319 gst_compositor_fill_checker_nv21 = GST_DEBUG_FUNCPTR (fill_checker_nv21);
1320 gst_compositor_fill_checker_y444 = GST_DEBUG_FUNCPTR (fill_checker_y444);
1321 gst_compositor_fill_checker_y42b = GST_DEBUG_FUNCPTR (fill_checker_y42b);
1322 gst_compositor_fill_checker_y41b = GST_DEBUG_FUNCPTR (fill_checker_y41b);
1323 gst_compositor_fill_checker_rgb = GST_DEBUG_FUNCPTR (fill_checker_rgb_c);
1324 gst_compositor_fill_checker_xrgb = GST_DEBUG_FUNCPTR (fill_checker_xrgb_c);
1325 gst_compositor_fill_checker_rgbx = GST_DEBUG_FUNCPTR (fill_checker_rgbx_c);
1326 gst_compositor_fill_checker_yuy2 = GST_DEBUG_FUNCPTR (fill_checker_yuy2_c);
1327 gst_compositor_fill_checker_uyvy = GST_DEBUG_FUNCPTR (fill_checker_uyvy_c);
1328 gst_compositor_fill_checker_i420_10le =
1329 GST_DEBUG_FUNCPTR (fill_checker_i420_10le);
1330 gst_compositor_fill_checker_i420_10be =
1331 GST_DEBUG_FUNCPTR (fill_checker_i420_10be);
1332 gst_compositor_fill_checker_i420_12le =
1333 GST_DEBUG_FUNCPTR (fill_checker_i420_12le);
1334 gst_compositor_fill_checker_i420_12be =
1335 GST_DEBUG_FUNCPTR (fill_checker_i420_12be);
1337 gst_compositor_fill_color_argb = GST_DEBUG_FUNCPTR (fill_color_argb);
1338 gst_compositor_fill_color_bgra = GST_DEBUG_FUNCPTR (fill_color_bgra);
1339 gst_compositor_fill_color_abgr = GST_DEBUG_FUNCPTR (fill_color_abgr);
1340 gst_compositor_fill_color_rgba = GST_DEBUG_FUNCPTR (fill_color_rgba);
1341 gst_compositor_fill_color_ayuv = GST_DEBUG_FUNCPTR (fill_color_ayuv);
1342 gst_compositor_fill_color_vuya = GST_DEBUG_FUNCPTR (fill_color_vuya);
1343 gst_compositor_fill_color_i420 = GST_DEBUG_FUNCPTR (fill_color_i420);
1344 gst_compositor_fill_color_yv12 = GST_DEBUG_FUNCPTR (fill_color_yv12);
1345 gst_compositor_fill_color_nv12 = GST_DEBUG_FUNCPTR (fill_color_nv12);
1346 gst_compositor_fill_color_y444 = GST_DEBUG_FUNCPTR (fill_color_y444);
1347 gst_compositor_fill_color_y42b = GST_DEBUG_FUNCPTR (fill_color_y42b);
1348 gst_compositor_fill_color_y41b = GST_DEBUG_FUNCPTR (fill_color_y41b);
1349 gst_compositor_fill_color_rgb = GST_DEBUG_FUNCPTR (fill_color_rgb_c);
1350 gst_compositor_fill_color_bgr = GST_DEBUG_FUNCPTR (fill_color_bgr_c);
1351 gst_compositor_fill_color_xrgb = GST_DEBUG_FUNCPTR (fill_color_xrgb);
1352 gst_compositor_fill_color_xbgr = GST_DEBUG_FUNCPTR (fill_color_xbgr);
1353 gst_compositor_fill_color_rgbx = GST_DEBUG_FUNCPTR (fill_color_rgbx);
1354 gst_compositor_fill_color_bgrx = GST_DEBUG_FUNCPTR (fill_color_bgrx);
1355 gst_compositor_fill_color_yuy2 = GST_DEBUG_FUNCPTR (fill_color_yuy2);
1356 gst_compositor_fill_color_yvyu = GST_DEBUG_FUNCPTR (fill_color_yvyu);
1357 gst_compositor_fill_color_uyvy = GST_DEBUG_FUNCPTR (fill_color_uyvy);
1358 gst_compositor_fill_color_i420_10le =
1359 GST_DEBUG_FUNCPTR (fill_color_i420_10le);
1360 gst_compositor_fill_color_i420_10be =
1361 GST_DEBUG_FUNCPTR (fill_color_i420_10be);
1362 gst_compositor_fill_color_i420_12le =
1363 GST_DEBUG_FUNCPTR (fill_color_i420_12le);
1364 gst_compositor_fill_color_i420_12be =
1365 GST_DEBUG_FUNCPTR (fill_color_i420_12be);