compositor: Add support for I420/I422 high bitdepth formats
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / gst / compositor / blend.c
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 A32_COLOR(name, A, C1, C2, C3) \
223 static void \
224 fill_color_##name (GstVideoFrame * frame, guint y_start, guint y_end, gint c1, gint c2, gint c3) \
225 { \
226   guint32 val; \
227   gint stride; \
228   guint8 *dest; \
229   \
230   dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
231   stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
232   \
233   dest += y_start * stride; \
234   val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
235   \
236   compositor_orc_splat_u32 ((guint32 *) dest, val, (y_end - y_start) * (stride / 4)); \
237 }
238
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);
245
246 /* Y444, Y42B, I420, YV12, Y41B */
247 #define PLANAR_YUV_BLEND(format_name,x_round,y_round,MEMCPY,BLENDLOOP,n_bits) \
248 inline static void \
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) \
252 { \
253   gint i; \
254   gint b_alpha; \
255   gint range; \
256   \
257   /* in source mode we just have to copy over things */ \
258   if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
259     src_alpha = 1.0; \
260   } \
261   \
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)"); \
265     return; \
266   } \
267   \
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); \
274       src += src_stride; \
275       dest += dest_stride; \
276     } \
277     return; \
278   } \
279   \
280   range = (1 << n_bits) - 1; \
281   b_alpha = CLAMP ((gint) (src_alpha * range), 0, range); \
282   \
283   BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height);\
284 } \
285 \
286 static void \
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) \
290 { \
291   const guint8 *b_src; \
292   guint8 *b_dest; \
293   gint b_src_width; \
294   gint b_src_height; \
295   gint xoffset = 0; \
296   gint yoffset = 0; \
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; \
305   gint pstride; \
306   \
307   src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
308   src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
309   \
310   info = srcframe->info.finfo; \
311   dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
312   dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
313   \
314   if (dst_y_end > dest_height) { \
315     dst_y_end = dest_height; \
316   } \
317   xpos = x_round (xpos); \
318   ypos = y_round (ypos); \
319   \
320   b_src_width = src_width; \
321   b_src_height = src_height; \
322   \
323   /* adjust src pointers for negative sizes */ \
324   if (xpos < 0) { \
325     xoffset = -xpos; \
326     b_src_width -= -xpos; \
327     xpos = 0; \
328   } \
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; \
333   } \
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) { \
336     return; \
337   } \
338   \
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; \
342   } \
343   if (ypos + b_src_height > dst_y_end) { \
344     b_src_height = dst_y_end - ypos; \
345   } \
346   if (b_src_width <= 0 || b_src_height <= 0) { \
347     return; \
348   } \
349   \
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, \
366       src_alpha, mode); \
367   \
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, \
383       src_alpha, mode); \
384   \
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, \
400       src_alpha, mode); \
401 }
402
403 #define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
404 static void \
405 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
406 { \
407   gint i, j; \
408   static const int tab[] = { 80, 160, 80, 160 }; \
409   guint8 *p; \
410   gint comp_width, comp_height; \
411   gint rowstride, comp_yoffset; \
412   const GstVideoFormatInfo *info; \
413   \
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; \
421   \
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)]; \
425     } \
426     p += rowstride - comp_width; \
427   } \
428   \
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; \
435   \
436   for (i = 0; i < comp_height; i++) { \
437     MEMSET (p, 0x80, comp_width); \
438     p += rowstride; \
439   } \
440   \
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; \
447   \
448   for (i = 0; i < comp_height; i++) { \
449     MEMSET (p, 0x80, comp_width); \
450     p += rowstride; \
451   } \
452 }
453
454 #define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
455 static void \
456 fill_color_##format_name (GstVideoFrame * frame, \
457     guint y_start, guint y_end, gint colY, gint colU, gint colV) \
458 { \
459   guint8 *p; \
460   gint comp_width, comp_height; \
461   gint rowstride, comp_yoffset; \
462   gint i; \
463   const GstVideoFormatInfo *info; \
464   \
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; \
472   \
473   for (i = 0; i < comp_height; i++) { \
474     MEMSET (p, colY, comp_width); \
475     p += rowstride; \
476   } \
477   \
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; \
484   \
485   for (i = 0; i < comp_height; i++) { \
486     MEMSET (p, colU, comp_width); \
487     p += rowstride; \
488   } \
489   \
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; \
496   \
497   for (i = 0; i < comp_height; i++) { \
498     MEMSET (p, colV, comp_width); \
499     p += rowstride; \
500   } \
501 }
502
503 #define PLANAR_YUV_HIGH_FILL_CHECKER(format_name, nbits, endian, MEMSET) \
504 static void \
505 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
506 { \
507   gint i, j; \
508   static const int tab[] = { 80 << (nbits - 8), 160 << (nbits - 8), 80 << (nbits - 8), 160 << (nbits - 8),}; \
509   guint8 *p; \
510   gint comp_width, comp_height; \
511   gint rowstride, comp_yoffset; \
512   gint pstride; \
513   gint uv; \
514   const GstVideoFormatInfo *info; \
515   \
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; \
524   \
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)]); \
528       p += pstride; \
529     } \
530     p += rowstride - comp_width * pstride; \
531   } \
532   \
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); \
542   \
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); \
551 }
552
553 #define PLANAR_YUV_HIGH_FILL_COLOR(format_name,endian,MEMSET) \
554 static void \
555 fill_color_##format_name (GstVideoFrame * frame, \
556     guint y_start, guint y_end, gint colY, gint colU, gint colV) \
557 { \
558   guint8 *p; \
559   gint comp_width, comp_height; \
560   gint rowstride, comp_yoffset; \
561   const GstVideoFormatInfo *info; \
562   \
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); \
571   \
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); \
579   \
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); \
587 }
588
589 #define GST_ROUND_UP_1(x) (x)
590
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);
608
609 #define BLEND_HIGH(format_name) \
610 compositor_orc_blend_##format_name
611
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);
617
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);
622
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);
627
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);
637
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);
642
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);
647
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 */
653
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);
658
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);
663
664 /* NV12, NV21 */
665 #define NV_YUV_BLEND(format_name,MEMCPY,BLENDLOOP) \
666 inline static void \
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) \
670 { \
671   gint i; \
672   gint b_alpha; \
673   \
674   /* in source mode we just have to copy over things */ \
675   if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
676     src_alpha = 1.0; \
677   } \
678   \
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)"); \
682     return; \
683   } \
684   \
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); \
690       src += src_stride; \
691       dest += dest_stride; \
692     } \
693     return; \
694   } \
695   \
696   b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
697   \
698   BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
699 } \
700 \
701 static void \
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)                    \
705 { \
706   const guint8 *b_src; \
707   guint8 *b_dest; \
708   gint b_src_width; \
709   gint b_src_height; \
710   gint xoffset = 0; \
711   gint yoffset = 0; \
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; \
720   \
721   src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
722   src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
723   \
724   info = srcframe->info.finfo; \
725   dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
726   dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
727   \
728   if (dst_y_end > dest_height) { \
729     dst_y_end = dest_height; \
730   } \
731   xpos = GST_ROUND_UP_2 (xpos); \
732   ypos = GST_ROUND_UP_2 (ypos); \
733   \
734   b_src_width = src_width; \
735   b_src_height = src_height; \
736   \
737   /* adjust src pointers for negative sizes */ \
738   if (xpos < 0) { \
739     xoffset = -xpos; \
740     b_src_width -= -xpos; \
741     xpos = 0; \
742   } \
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; \
747   } \
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) { \
750     return; \
751   } \
752   \
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; \
756   } \
757   if (ypos + b_src_height > dst_y_end) { \
758     b_src_height = dst_y_end - ypos; \
759   } \
760   if (b_src_width < 0 || b_src_height < 0) { \
761     return; \
762   } \
763   \
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, \
779       src_alpha, mode); \
780   \
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, \
795       src_alpha, mode); \
796 }
797
798 #define NV_YUV_FILL_CHECKER(format_name, MEMSET)        \
799 static void \
800 fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
801 { \
802   gint i, j; \
803   static const int tab[] = { 80, 160, 80, 160 }; \
804   guint8 *p; \
805   gint comp_width, comp_height; \
806   gint rowstride, comp_yoffset; \
807   const GstVideoFormatInfo *info; \
808   \
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; \
816   \
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)]; \
820     } \
821     p += rowstride - comp_width; \
822   } \
823   \
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; \
830   \
831   for (i = 0; i < comp_height; i++) { \
832     MEMSET (p, 0x80, comp_width * 2); \
833     p += rowstride; \
834   } \
835 }
836
837 #define NV_YUV_FILL_COLOR(format_name,MEMSET) \
838 static void \
839 fill_color_##format_name (GstVideoFrame * frame, \
840     guint y_start, guint y_end, gint colY, gint colU, gint colV) \
841 { \
842   guint8 *y, *u, *v; \
843   gint comp_width, comp_height; \
844   gint rowstride, comp_yoffset; \
845   gint i, j; \
846   const GstVideoFormatInfo *info; \
847   \
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); \
854   \
855   y += comp_yoffset * rowstride; \
856   for (i = 0; i < comp_height; i++) { \
857     MEMSET (y, colY, comp_width); \
858     y += rowstride; \
859   } \
860   \
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]; \
867   \
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++) { \
872       u[j*2] = colU; \
873       v[j*2] = colV; \
874     } \
875     u += rowstride; \
876     v += rowstride; \
877   } \
878 }
879
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);
885
886 /* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
887
888 #define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
889 static void \
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) \
893 { \
894   gint b_alpha; \
895   gint i; \
896   gint src_stride, dest_stride; \
897   gint dest_width, dest_height; \
898   guint8 *dest, *src; \
899   gint src_width, src_height; \
900   \
901   src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
902   src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
903   \
904   src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
905   dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
906   \
907   dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
908   dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
909   \
910   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
911   dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
912   \
913   b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
914   \
915   if (dst_y_end > dest_height) { \
916     dst_y_end = dest_height; \
917   } \
918   /* adjust src pointers for negative sizes */ \
919   if (xpos < 0) { \
920     src += -xpos * bpp; \
921     src_width -= -xpos; \
922     xpos = 0; \
923   } \
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; \
928   } \
929   /* adjust width/height if the src is bigger than dest */ \
930   if (xpos + src_width > dest_width) { \
931     src_width = dest_width - xpos; \
932   } \
933   if (ypos + src_height > dst_y_end) { \
934     src_height = dst_y_end - ypos; \
935   } \
936   \
937   dest = dest + bpp * xpos + (ypos * dest_stride); \
938   \
939   /* in source mode we just have to copy over things */ \
940   if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
941     src_alpha = 1.0; \
942   } \
943   \
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)"); \
947     return; \
948   } \
949   \
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); \
955       src += src_stride; \
956       dest += dest_stride; \
957     } \
958     return; \
959   } \
960   \
961   BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
962 }
963
964 #define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
965 static void \
966 fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
967 { \
968   gint i, j; \
969   static const int tab[] = { 80, 160, 80, 160 }; \
970   gint stride, dest_add, width, height; \
971   guint8 *dest; \
972   \
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; \
978   \
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 */ \
985       dest += bpp; \
986     } \
987     dest += dest_add; \
988   } \
989 }
990
991 #define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
992 static void \
993 fill_color_##name (GstVideoFrame * frame, \
994     guint y_start, guint y_end, gint colR, gint colG, gint colB) \
995 { \
996   gint i; \
997   gint dest_stride; \
998   gint width, height; \
999   guint8 *dest; \
1000   \
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); \
1005   \
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; \
1010   } \
1011 }
1012
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) { \
1016   gint j; \
1017   \
1018   for (j = 0; j < width; j++) { \
1019     dest[r] = red; \
1020     dest[g] = green; \
1021     dest[b] = blue; \
1022     dest += 3; \
1023   } \
1024 }
1025
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) { \
1029   guint32 val; \
1030   \
1031   val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
1032   compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
1033 }
1034
1035 #define _orc_memcpy_u32(dest,src,len) compositor_orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
1036
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);
1041
1042 MEMSET_RGB_C (bgr, 2, 1, 0);
1043 RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
1044
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);
1049
1050 MEMSET_XRGB (xbgr, 0, 16, 24);
1051 RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
1052
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);
1056
1057 MEMSET_XRGB (bgrx, 8, 16, 24);
1058 RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
1059
1060 /* YUY2, YVYU, UYVY */
1061
1062 #define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
1063 static void \
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) \
1067 { \
1068   gint b_alpha; \
1069   gint i; \
1070   gint src_stride, dest_stride; \
1071   gint dest_width, dest_height; \
1072   guint8 *src, *dest; \
1073   gint src_width, src_height; \
1074   \
1075   src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
1076   src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
1077   \
1078   dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
1079   dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
1080   \
1081   src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
1082   dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
1083   \
1084   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
1085   dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
1086   \
1087   b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
1088   \
1089   xpos = GST_ROUND_UP_2 (xpos); \
1090   \
1091   if (dst_y_end > dest_height) { \
1092     dst_y_end = dest_height; \
1093   } \
1094   /* adjust src pointers for negative sizes */ \
1095   if (xpos < 0) { \
1096     src += -xpos * 2; \
1097     src_width -= -xpos; \
1098     xpos = 0; \
1099   } \
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; \
1104   } \
1105   \
1106   /* adjust width/height if the src is bigger than dest */ \
1107   if (xpos + src_width > dest_width) { \
1108     src_width = dest_width - xpos; \
1109   } \
1110   if (ypos + src_height > dst_y_end) { \
1111     src_height = dst_y_end - ypos; \
1112   } \
1113   \
1114   dest = dest + 2 * xpos + (ypos * dest_stride); \
1115   \
1116   /* in source mode we just have to copy over things */ \
1117   if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
1118     src_alpha = 1.0; \
1119   } \
1120   \
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)"); \
1124     return; \
1125   } \
1126   \
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; \
1134     } \
1135     return; \
1136   } \
1137   \
1138   BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
1139 }
1140
1141 #define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
1142 static void \
1143 fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
1144 { \
1145   gint i, j; \
1146   static const int tab[] = { 80, 160, 80, 160 }; \
1147   gint dest_add; \
1148   gint width, height; \
1149   guint8 *dest; \
1150   \
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; \
1156   width /= 2; \
1157   \
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)]; \
1163       dest[U] = 128; \
1164       dest[V] = 128; \
1165       dest += 4; \
1166     } \
1167     dest += dest_add; \
1168   } \
1169 }
1170
1171 #define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
1172 static void \
1173 fill_color_##name (GstVideoFrame * frame, \
1174     guint y_start, guint y_end, gint colY, gint colU, gint colV) \
1175 { \
1176   gint i; \
1177   gint dest_stride; \
1178   guint32 val; \
1179   gint width, height; \
1180   guint8 *dest; \
1181   \
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); \
1187   width /= 2; \
1188   \
1189   val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
1190   \
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; \
1195   } \
1196 }
1197
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);
1204
1205 /* Init function */
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;
1232
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;
1257
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;
1284
1285 void
1286 gst_compositor_init_blend (void)
1287 {
1288   GST_DEBUG_CATEGORY_INIT (gst_compositor_blend_debug, "compositor_blend", 0,
1289       "video compositor blending functions");
1290
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);
1312
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);
1336
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);
1366 }