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