Commit 11fa711c authored by Mathieu Duponchelle's avatar Mathieu Duponchelle Committed by Thibault Saunier

compositor: Add a new compositor based on the new GstVideoAggregator base class

It is a replacement for videomixer with a similare API

Co-Authored by: Thibault Saunier <tsaunier@gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=731919
parent 4ce8b409
......@@ -430,6 +430,7 @@ AG_GST_CHECK_PLUGIN(aiff)
AG_GST_CHECK_PLUGIN(asfmux)
AG_GST_CHECK_PLUGIN(audiofxbad)
AG_GST_CHECK_PLUGIN(audiomixer)
AG_GST_CHECK_PLUGIN(compositor)
AG_GST_CHECK_PLUGIN(audiovisualizers)
AG_GST_CHECK_PLUGIN(autoconvert)
AG_GST_CHECK_PLUGIN(bayer)
......@@ -3202,6 +3203,7 @@ gst/videosignal/Makefile
gst/vmnc/Makefile
gst/y4m/Makefile
gst/yadif/Makefile
gst/compositor/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
gst-libs/gst/basecamerabinsrc/Makefile
......
......@@ -26,6 +26,7 @@
<xi:include href="xml/element-chromium.xml" />
<xi:include href="xml/element-circle.xml" />
<xi:include href="xml/element-coloreffects.xml" />
<xi:include href="xml/element-compositor.xml" />
<xi:include href="xml/element-cvdilate.xml" />
<xi:include href="xml/element-cverode.xml" />
<xi:include href="xml/element-cvequalizehist.xml" />
......
......@@ -1624,6 +1624,26 @@ GST_IS_GL_TRANSFORMATION_CLASS
GST_TYPE_GL_TRANSFORMATION
</SECTION>
<SECTION>
<FILE>element-compositor</FILE>
<TITLE>compositor</TITLE>
<SUBSECTION Standard>
GstCompositorClass
GstCompositor
GST_COMPOSITOR
GST_COMPOSITOR_CLASS
GST_IS_COMPOSITOR
GST_IS_COMPOSITOR_CLASS
GST_TYPE_COMPOSITOR
GstCompositorPad
GstCompositorPadClass
GST_COMPOSITOR_PAD
GST_COMPOSITOR_PAD_CLASS
GST_IS_COMPOSITOR_PAD
GST_IS_COMPOSITOR_PAD_CLASS
GST_TYPE_COMPOSITOR_PAD
</SECTION>
# gst-libs
<SECTION>
......
plugin_LTLIBRARIES = libgstcompositor.la
ORC_SOURCE=compositororc
include $(top_srcdir)/common/orc.mak
libgstcompositor_la_SOURCES = \
blend.c \
compositor.c
nodist_libgstcompositor_la_SOURCES = $(ORC_NODIST_SOURCES)
libgstcompositor_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
-I$(top_srcdir)/gst-libs \
-I$(top_builddir)/gst-libs \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ORC_CFLAGS)
libgstcompositor_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstvideo-@GST_API_VERSION@ \
$(top_builddir)/gst-libs/gst/base/libgstbadbase-$(GST_API_VERSION).la \
$(top_builddir)/gst-libs/gst/video/libgstbadvideo-$(GST_API_VERSION).la \
$(GST_BASE_LIBS) $(GST_LIBS) $(ORC_LIBS) $(LIBM)
libgstcompositor_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstcompositor_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
# headers we need but don't want installed
noinst_HEADERS = \
blend.h \
compositor.h \
compositorpad.h
/*
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
* Copyright (C) 2006 Mindfruit Bv.
* Author: Sjoerd Simons <sjoerd@luon.net>
* Author: Alex Ugarte <alexugarte@gmail.com>
* Copyright (C) 2009 Alex Ugarte <augarte@vicomtech.org>
* Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "blend.h"
#include "compositororc.h"
#include <string.h>
#include <gst/video/video.h>
#define BLEND(D,S,alpha) (((D) * (256 - (alpha)) + (S) * (alpha)) >> 8)
GST_DEBUG_CATEGORY_STATIC (gst_compositor_blend_debug);
#define GST_CAT_DEFAULT gst_compositor_blend_debug
/* Below are the implementations of everything */
/* A32 is for AYUV, ARGB and BGRA */
#define BLEND_A32(name, method, LOOP) \
static void \
method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
gdouble src_alpha, GstVideoFrame * destframe) \
{ \
guint s_alpha; \
gint src_stride, dest_stride; \
gint dest_width, dest_height; \
guint8 *src, *dest; \
gint src_width, src_height; \
\
src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
dest_width = GST_VIDEO_FRAME_COMP_WIDTH (destframe, 0); \
dest_height = GST_VIDEO_FRAME_COMP_HEIGHT (destframe, 0); \
\
s_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
\
/* If it's completely transparent... we just return */ \
if (G_UNLIKELY (s_alpha == 0)) \
return; \
\
/* adjust src pointers for negative sizes */ \
if (xpos < 0) { \
src += -xpos * 4; \
src_width -= -xpos; \
xpos = 0; \
} \
if (ypos < 0) { \
src += -ypos * src_stride; \
src_height -= -ypos; \
ypos = 0; \
} \
/* adjust width/height if the src is bigger than dest */ \
if (xpos + src_width > dest_width) { \
src_width = dest_width - xpos; \
} \
if (ypos + src_height > dest_height) { \
src_height = dest_height - ypos; \
} \
\
dest = dest + 4 * xpos + (ypos * dest_stride); \
\
LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha); \
}
#define BLEND_A32_LOOP(name, method) \
static inline void \
_##method##_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
gint src_width, gint src_stride, gint dest_stride, guint s_alpha) \
{ \
s_alpha = MIN (255, s_alpha); \
compositor_orc_##method##_##name (dest, dest_stride, src, src_stride, \
s_alpha, src_width, src_height); \
}
BLEND_A32_LOOP (argb, blend);
BLEND_A32_LOOP (bgra, blend);
BLEND_A32_LOOP (argb, overlay);
BLEND_A32_LOOP (bgra, overlay);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
BLEND_A32 (argb, blend, _blend_loop_argb);
BLEND_A32 (bgra, blend, _blend_loop_bgra);
BLEND_A32 (argb, overlay, _overlay_loop_argb);
BLEND_A32 (bgra, overlay, _overlay_loop_bgra);
#else
BLEND_A32 (argb, blend, _blend_loop_bgra);
BLEND_A32 (bgra, blend, _blend_loop_argb);
BLEND_A32 (argb, overlay, _overlay_loop_bgra);
BLEND_A32 (bgra, overlay, _overlay_loop_argb);
#endif
#define A32_CHECKER_C(name, RGB, A, C1, C2, C3) \
static void \
fill_checker_##name##_c (GstVideoFrame * frame) \
{ \
gint i, j; \
gint val; \
static const gint tab[] = { 80, 160, 80, 160 }; \
gint width, height; \
guint8 *dest; \
\
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
\
if (!RGB) { \
for (i = 0; i < height; i++) { \
for (j = 0; j < width; j++) { \
dest[A] = 0xff; \
dest[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
dest[C2] = 128; \
dest[C3] = 128; \
dest += 4; \
} \
} \
} else { \
for (i = 0; i < height; i++) { \
for (j = 0; j < width; j++) { \
val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
dest[A] = 0xFF; \
dest[C1] = val; \
dest[C2] = val; \
dest[C3] = val; \
dest += 4; \
} \
} \
} \
}
A32_CHECKER_C (argb, TRUE, 0, 1, 2, 3);
A32_CHECKER_C (bgra, TRUE, 3, 2, 1, 0);
A32_CHECKER_C (ayuv, FALSE, 0, 1, 2, 3);
#define YUV_TO_R(Y,U,V) (CLAMP (1.164 * (Y - 16) + 1.596 * (V - 128), 0, 255))
#define YUV_TO_G(Y,U,V) (CLAMP (1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128), 0, 255))
#define YUV_TO_B(Y,U,V) (CLAMP (1.164 * (Y - 16) + 2.018 * (U - 128), 0, 255))
#define A32_COLOR(name, RGB, A, C1, C2, C3) \
static void \
fill_color_##name (GstVideoFrame * frame, gint Y, gint U, gint V) \
{ \
gint c1, c2, c3; \
guint32 val; \
gint width, height; \
guint8 *dest; \
\
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
\
if (RGB) { \
c1 = YUV_TO_R (Y, U, V); \
c2 = YUV_TO_G (Y, U, V); \
c3 = YUV_TO_B (Y, U, V); \
} else { \
c1 = Y; \
c2 = U; \
c3 = V; \
} \
val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
\
compositor_orc_splat_u32 ((guint32 *) dest, val, height * width); \
}
A32_COLOR (argb, TRUE, 24, 16, 8, 0);
A32_COLOR (bgra, TRUE, 0, 8, 16, 24);
A32_COLOR (abgr, TRUE, 24, 0, 8, 16);
A32_COLOR (rgba, TRUE, 0, 24, 16, 8);
A32_COLOR (ayuv, FALSE, 24, 16, 8, 0);
/* Y444, Y42B, I420, YV12, Y41B */
#define PLANAR_YUV_BLEND(format_name,format_enum,x_round,y_round,MEMCPY,BLENDLOOP) \
inline static void \
_blend_##format_name (const guint8 * src, guint8 * dest, \
gint src_stride, gint dest_stride, gint src_width, gint src_height, \
gdouble src_alpha) \
{ \
gint i; \
gint b_alpha; \
\
/* If it's completely transparent... we just return */ \
if (G_UNLIKELY (src_alpha == 0.0)) { \
GST_INFO ("Fast copy (alpha == 0.0)"); \
return; \
} \
\
/* If it's completely opaque, we do a fast copy */ \
if (G_UNLIKELY (src_alpha == 1.0)) { \
GST_INFO ("Fast copy (alpha == 1.0)"); \
for (i = 0; i < src_height; i++) { \
MEMCPY (dest, src, src_width); \
src += src_stride; \
dest += dest_stride; \
} \
return; \
} \
\
b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
\
BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
} \
\
static void \
blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
gdouble src_alpha, GstVideoFrame * destframe) \
{ \
const guint8 *b_src; \
guint8 *b_dest; \
gint b_src_width; \
gint b_src_height; \
gint xoffset = 0; \
gint yoffset = 0; \
gint src_comp_rowstride, dest_comp_rowstride; \
gint src_comp_height; \
gint src_comp_width; \
gint comp_ypos, comp_xpos; \
gint comp_yoffset, comp_xoffset; \
gint dest_width, dest_height; \
const GstVideoFormatInfo *info; \
gint src_width, src_height; \
\
src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
\
info = srcframe->info.finfo; \
dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
\
xpos = x_round (xpos); \
ypos = y_round (ypos); \
\
b_src_width = src_width; \
b_src_height = src_height; \
\
/* adjust src pointers for negative sizes */ \
if (xpos < 0) { \
xoffset = -xpos; \
b_src_width -= -xpos; \
xpos = 0; \
} \
if (ypos < 0) { \
yoffset += -ypos; \
b_src_height -= -ypos; \
ypos = 0; \
} \
/* If x or y offset are larger then the source it's outside of the picture */ \
if (xoffset > src_width || yoffset > src_height) { \
return; \
} \
\
/* adjust width/height if the src is bigger than dest */ \
if (xpos + src_width > dest_width) { \
b_src_width = dest_width - xpos; \
} \
if (ypos + src_height > dest_height) { \
b_src_height = dest_height - ypos; \
} \
if (b_src_width < 0 || b_src_height < 0) { \
return; \
} \
\
/* First mix Y, then U, then V */ \
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
_blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
src_comp_rowstride, \
dest_comp_rowstride, src_comp_width, src_comp_height, \
src_alpha); \
\
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 1); \
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 1); \
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 1); \
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 1, b_src_width); \
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, b_src_height); \
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, ypos); \
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 1, yoffset); \
_blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
src_comp_rowstride, \
dest_comp_rowstride, src_comp_width, src_comp_height, \
src_alpha); \
\
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 2); \
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 2); \
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 2); \
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 2); \
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 2, b_src_width); \
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, b_src_height); \
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xpos); \
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, ypos); \
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xoffset); \
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 2, yoffset); \
_blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
src_comp_rowstride, \
dest_comp_rowstride, src_comp_width, src_comp_height, \
src_alpha); \
}
#define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
static void \
fill_checker_##format_name (GstVideoFrame * frame) \
{ \
gint i, j; \
static const int tab[] = { 80, 160, 80, 160 }; \
guint8 *p; \
gint comp_width, comp_height; \
gint rowstride; \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
\
for (i = 0; i < comp_height; i++) { \
for (j = 0; j < comp_width; j++) { \
*p++ = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
} \
p += rowstride - comp_width; \
} \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
\
for (i = 0; i < comp_height; i++) { \
MEMSET (p, 0x80, comp_width); \
p += rowstride; \
} \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
\
for (i = 0; i < comp_height; i++) { \
MEMSET (p, 0x80, comp_width); \
p += rowstride; \
} \
}
#define PLANAR_YUV_FILL_COLOR(format_name,format_enum,MEMSET) \
static void \
fill_color_##format_name (GstVideoFrame * frame, \
gint colY, gint colU, gint colV) \
{ \
guint8 *p; \
gint comp_width, comp_height; \
gint rowstride; \
gint i; \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
\
for (i = 0; i < comp_height; i++) { \
MEMSET (p, colY, comp_width); \
p += rowstride; \
} \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
\
for (i = 0; i < comp_height; i++) { \
MEMSET (p, colU, comp_width); \
p += rowstride; \
} \
\
p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
comp_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 2); \
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
\
for (i = 0; i < comp_height; i++) { \
MEMSET (p, colV, comp_width); \
p += rowstride; \
} \
}
#define GST_ROUND_UP_1(x) (x)
PLANAR_YUV_BLEND (i420, GST_VIDEO_FORMAT_I420, GST_ROUND_UP_2,
GST_ROUND_UP_2, memcpy, compositor_orc_blend_u8);
PLANAR_YUV_FILL_CHECKER (i420, GST_VIDEO_FORMAT_I420, memset);
PLANAR_YUV_FILL_COLOR (i420, GST_VIDEO_FORMAT_I420, memset);
PLANAR_YUV_FILL_COLOR (yv12, GST_VIDEO_FORMAT_YV12, memset);
PLANAR_YUV_BLEND (y444, GST_VIDEO_FORMAT_Y444, GST_ROUND_UP_1,
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
PLANAR_YUV_FILL_CHECKER (y444, GST_VIDEO_FORMAT_Y444, memset);
PLANAR_YUV_FILL_COLOR (y444, GST_VIDEO_FORMAT_Y444, memset);
PLANAR_YUV_BLEND (y42b, GST_VIDEO_FORMAT_Y42B, GST_ROUND_UP_2,
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
PLANAR_YUV_FILL_CHECKER (y42b, GST_VIDEO_FORMAT_Y42B, memset);
PLANAR_YUV_FILL_COLOR (y42b, GST_VIDEO_FORMAT_Y42B, memset);
PLANAR_YUV_BLEND (y41b, GST_VIDEO_FORMAT_Y41B, GST_ROUND_UP_4,
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8);
PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
/* NV12, NV21 */
#define NV_YUV_BLEND(format_name,MEMCPY,BLENDLOOP) \
inline static void \
_blend_##format_name (const guint8 * src, guint8 * dest, \
gint src_stride, gint dest_stride, gint src_width, gint src_height, \
gdouble src_alpha) \
{ \
gint i; \
gint b_alpha; \
\
/* If it's completely transparent... we just return */ \
if (G_UNLIKELY (src_alpha == 0.0)) { \
GST_INFO ("Fast copy (alpha == 0.0)"); \
return; \
} \
\
/* If it's completely opaque, we do a fast copy */ \
if (G_UNLIKELY (src_alpha == 1.0)) { \
GST_INFO ("Fast copy (alpha == 1.0)"); \
for (i = 0; i < src_height; i++) { \
MEMCPY (dest, src, src_width); \
src += src_stride; \
dest += dest_stride; \
} \
return; \
} \
\
b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
\
BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
} \
\
static void \
blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
gdouble src_alpha, GstVideoFrame * destframe) \
{ \
const guint8 *b_src; \
guint8 *b_dest; \
gint b_src_width; \
gint b_src_height; \
gint xoffset = 0; \
gint yoffset = 0; \
gint src_comp_rowstride, dest_comp_rowstride; \
gint src_comp_height; \
gint src_comp_width; \
gint comp_ypos, comp_xpos; \
gint comp_yoffset, comp_xoffset; \
gint dest_width, dest_height; \
const GstVideoFormatInfo *info; \
gint src_width, src_height; \
\
src_width = GST_VIDEO_FRAME_WIDTH (srcframe); \
src_height = GST_VIDEO_FRAME_HEIGHT (srcframe); \
\
info = srcframe->info.finfo; \
dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
\
xpos = GST_ROUND_UP_2 (xpos); \
ypos = GST_ROUND_UP_2 (ypos); \
\
b_src_width = src_width; \
b_src_height = src_height; \
\
/* adjust src pointers for negative sizes */ \
if (xpos < 0) { \
xoffset = -xpos; \
b_src_width -= -xpos; \
xpos = 0; \
} \
if (ypos < 0) { \
yoffset += -ypos; \
b_src_height -= -ypos; \
ypos = 0; \
} \
/* If x or y offset are larger then the source it's outside of the picture */ \
if (xoffset > src_width || yoffset > src_height) { \
return; \
} \
\
/* adjust width/height if the src is bigger than dest */ \
if (xpos + src_width > dest_width) { \
b_src_width = dest_width - xpos; \
} \
if (ypos + src_height > dest_height) { \
b_src_height = dest_height - ypos; \
} \
if (b_src_width < 0 || b_src_height < 0) { \
return; \
} \
\
/* First mix Y, then UV */ \
b_src = GST_VIDEO_FRAME_COMP_DATA (srcframe, 0); \
b_dest = GST_VIDEO_FRAME_COMP_DATA (destframe, 0); \
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
dest_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
src_comp_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(info, 0, b_src_width); \
src_comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, b_src_height); \
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xpos); \
comp_ypos = (ypos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, ypos); \
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 0, xoffset); \
comp_yoffset = (yoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, yoffset); \
_blend_##format_name (b_src + comp_xoffset + comp_yoffset * src_comp_rowstride, \
b_dest + comp_xpos + comp_ypos * dest_comp_rowstride, \
src_comp_rowstride, \
dest_comp_rowstride, src_comp_width, src_comp_height, \
src_alpha); \
\
b_src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 1); \
b_dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 1); \
src_comp_rowstride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 1); \