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