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