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