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