summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gst-libs/gst/video/gstvideoaggregator.c13
-rw-r--r--gst-libs/gst/video/gstvideoaggregatorpad.h7
-rw-r--r--gst/compositor/blend.c145
-rw-r--r--gst/compositor/blend.h24
-rw-r--r--gst/compositor/compositor.c194
-rw-r--r--gst/compositor/compositor.h5
-rw-r--r--gst/compositor/compositororc.orc144
-rw-r--r--gst/compositor/compositorpad.h3
8 files changed, 433 insertions, 102 deletions
diff --git a/gst-libs/gst/video/gstvideoaggregator.c b/gst-libs/gst/video/gstvideoaggregator.c
index 0de0bc6c4..9864612ac 100644
--- a/gst-libs/gst/video/gstvideoaggregator.c
+++ b/gst-libs/gst/video/gstvideoaggregator.c
@@ -521,7 +521,18 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
GINT_TO_POINTER (format_number));
/* If that pad is the first with alpha, set it as the new best format */
- if (!need_alpha && (pad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
+ if (!need_alpha && (pad->ABI.needs_alpha
+ && (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (pad->info.finfo)))) {
+ need_alpha = TRUE;
+ /* Just fallback to ARGB in case we require alpha but the input pad
+ * does not have alpha.
+ * Do not increment best_format_number in that case. */
+ gst_video_info_set_format (best_info,
+ GST_VIDEO_FORMAT_ARGB,
+ GST_VIDEO_INFO_HEIGHT (&pad->info),
+ GST_VIDEO_INFO_WIDTH (&pad->info));
+ } else if (!need_alpha
+ && (pad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
need_alpha = TRUE;
*best_info = pad->info;
best_format_number = format_number;
diff --git a/gst-libs/gst/video/gstvideoaggregatorpad.h b/gst-libs/gst/video/gstvideoaggregatorpad.h
index 2a3ee4411..c37473118 100644
--- a/gst-libs/gst/video/gstvideoaggregatorpad.h
+++ b/gst-libs/gst/video/gstvideoaggregatorpad.h
@@ -70,7 +70,12 @@ struct _GstVideoAggregatorPad
/* < private > */
GstVideoAggregatorPadPrivate *priv;
- gpointer _gst_reserved[GST_PADDING];
+ union {
+ /* Subclasses can force an alpha channel in the (input thus output)
+ * colorspace format */
+ gboolean needs_alpha;
+ gpointer _gst_reserved[GST_PADDING];
+ } ABI;
};
/**
diff --git a/gst/compositor/blend.c b/gst/compositor/blend.c
index 721c766e6..b36c16465 100644
--- a/gst/compositor/blend.c
+++ b/gst/compositor/blend.c
@@ -44,7 +44,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_compositor_blend_debug);
#define BLEND_A32(name, method, LOOP) \
static void \
method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
- gdouble src_alpha, GstVideoFrame * destframe) \
+ gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
{ \
guint s_alpha; \
gint src_stride, dest_stride; \
@@ -89,24 +89,45 @@ method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
if (src_height > 0 && src_width > 0) { \
dest = dest + 4 * xpos + (ypos * dest_stride); \
\
- LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha); \
+ LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha, \
+ mode); \
} \
}
-#define BLEND_A32_LOOP(name, method) \
+#define OVERLAY_A32_LOOP(name) \
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) \
+_overlay_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
+ gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
+ GstCompositorBlendMode mode) \
{ \
s_alpha = MIN (255, s_alpha); \
- compositor_orc_##method##_##name (dest, dest_stride, src, src_stride, \
- s_alpha, src_width, src_height); \
+ switch (mode) { \
+ case COMPOSITOR_BLEND_MODE_NORMAL:\
+ compositor_orc_overlay_##name (dest, dest_stride, src, src_stride, \
+ s_alpha, src_width, src_height); \
+ break;\
+ case COMPOSITOR_BLEND_MODE_ADDITIVE:\
+ compositor_orc_overlay_##name##_addition (dest, dest_stride, src, src_stride, \
+ s_alpha, src_width, src_height); \
+ break;\
+ }\
}
-BLEND_A32_LOOP (argb, blend);
-BLEND_A32_LOOP (bgra, blend);
-BLEND_A32_LOOP (argb, overlay);
-BLEND_A32_LOOP (bgra, overlay);
+#define BLEND_A32_LOOP_WITH_MODE(name) \
+static inline void \
+_blend_loop_##name (guint8 * dest, const guint8 * src, gint src_height, \
+ gint src_width, gint src_stride, gint dest_stride, guint s_alpha, \
+ GstCompositorBlendMode mode) \
+{ \
+ s_alpha = MIN (255, s_alpha); \
+ compositor_orc_blend_##name (dest, dest_stride, src, src_stride, \
+ s_alpha, src_width, src_height); \
+}
+
+OVERLAY_A32_LOOP (argb);
+OVERLAY_A32_LOOP (bgra);
+BLEND_A32_LOOP_WITH_MODE (argb);
+BLEND_A32_LOOP_WITH_MODE (bgra);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
BLEND_A32 (argb, blend, _blend_loop_argb);
@@ -228,12 +249,12 @@ _blend_##format_name (const guint8 * src, guint8 * dest, \
\
b_alpha = CLAMP ((gint) (src_alpha * 256), 0, 256); \
\
- BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width, src_height); \
+ 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) \
+ gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
{ \
const guint8 *b_src; \
guint8 *b_dest; \
@@ -478,7 +499,7 @@ _blend_##format_name (const guint8 * src, guint8 * dest, \
\
static void \
blend_##format_name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
- gdouble src_alpha, GstVideoFrame * destframe) \
+ gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
{ \
const guint8 *b_src; \
guint8 *b_dest; \
@@ -649,7 +670,7 @@ NV_YUV_FILL_CHECKER (nv21, memset);
#define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
static void \
blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
- gdouble src_alpha, GstVideoFrame * destframe) \
+ gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
{ \
gint b_alpha; \
gint i; \
@@ -815,7 +836,7 @@ RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
#define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
static void \
blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
- gdouble src_alpha, GstVideoFrame * destframe) \
+ gdouble src_alpha, GstVideoFrame * destframe, GstCompositorBlendMode mode) \
{ \
gint b_alpha; \
gint i; \
@@ -1010,52 +1031,52 @@ gst_compositor_init_blend (void)
GST_DEBUG_CATEGORY_INIT (gst_compositor_blend_debug, "compositor_blend", 0,
"video compositor blending functions");
- gst_compositor_blend_argb = blend_argb;
- gst_compositor_blend_bgra = blend_bgra;
- gst_compositor_overlay_argb = overlay_argb;
- gst_compositor_overlay_bgra = overlay_bgra;
- gst_compositor_blend_i420 = blend_i420;
- gst_compositor_blend_nv12 = blend_nv12;
- gst_compositor_blend_nv21 = blend_nv21;
- gst_compositor_blend_y444 = blend_y444;
- gst_compositor_blend_y42b = blend_y42b;
- gst_compositor_blend_y41b = blend_y41b;
- gst_compositor_blend_rgb = blend_rgb;
- gst_compositor_blend_xrgb = blend_xrgb;
- gst_compositor_blend_yuy2 = blend_yuy2;
+ gst_compositor_blend_argb = GST_DEBUG_FUNCPTR (blend_argb);
+ gst_compositor_blend_bgra = GST_DEBUG_FUNCPTR (blend_bgra);
+ gst_compositor_overlay_argb = GST_DEBUG_FUNCPTR (overlay_argb);
+ gst_compositor_overlay_bgra = GST_DEBUG_FUNCPTR (overlay_bgra);
+ gst_compositor_blend_i420 = GST_DEBUG_FUNCPTR (blend_i420);
+ gst_compositor_blend_nv12 = GST_DEBUG_FUNCPTR (blend_nv12);
+ gst_compositor_blend_nv21 = GST_DEBUG_FUNCPTR (blend_nv21);
+ gst_compositor_blend_y444 = GST_DEBUG_FUNCPTR (blend_y444);
+ gst_compositor_blend_y42b = GST_DEBUG_FUNCPTR (blend_y42b);
+ gst_compositor_blend_y41b = GST_DEBUG_FUNCPTR (blend_y41b);
+ gst_compositor_blend_rgb = GST_DEBUG_FUNCPTR (blend_rgb);
+ gst_compositor_blend_xrgb = GST_DEBUG_FUNCPTR (blend_xrgb);
+ gst_compositor_blend_yuy2 = GST_DEBUG_FUNCPTR (blend_yuy2);
- gst_compositor_fill_checker_argb = fill_checker_argb_c;
- gst_compositor_fill_checker_bgra = fill_checker_bgra_c;
- gst_compositor_fill_checker_ayuv = fill_checker_ayuv_c;
- gst_compositor_fill_checker_i420 = fill_checker_i420;
- gst_compositor_fill_checker_nv12 = fill_checker_nv12;
- gst_compositor_fill_checker_nv21 = fill_checker_nv21;
- gst_compositor_fill_checker_y444 = fill_checker_y444;
- gst_compositor_fill_checker_y42b = fill_checker_y42b;
- gst_compositor_fill_checker_y41b = fill_checker_y41b;
- gst_compositor_fill_checker_rgb = fill_checker_rgb_c;
- gst_compositor_fill_checker_xrgb = fill_checker_xrgb_c;
- gst_compositor_fill_checker_yuy2 = fill_checker_yuy2_c;
- gst_compositor_fill_checker_uyvy = fill_checker_uyvy_c;
+ gst_compositor_fill_checker_argb = GST_DEBUG_FUNCPTR (fill_checker_argb_c);
+ gst_compositor_fill_checker_bgra = GST_DEBUG_FUNCPTR (fill_checker_bgra_c);
+ gst_compositor_fill_checker_ayuv = GST_DEBUG_FUNCPTR (fill_checker_ayuv_c);
+ gst_compositor_fill_checker_i420 = GST_DEBUG_FUNCPTR (fill_checker_i420);
+ gst_compositor_fill_checker_nv12 = GST_DEBUG_FUNCPTR (fill_checker_nv12);
+ gst_compositor_fill_checker_nv21 = GST_DEBUG_FUNCPTR (fill_checker_nv21);
+ gst_compositor_fill_checker_y444 = GST_DEBUG_FUNCPTR (fill_checker_y444);
+ gst_compositor_fill_checker_y42b = GST_DEBUG_FUNCPTR (fill_checker_y42b);
+ gst_compositor_fill_checker_y41b = GST_DEBUG_FUNCPTR (fill_checker_y41b);
+ gst_compositor_fill_checker_rgb = GST_DEBUG_FUNCPTR (fill_checker_rgb_c);
+ gst_compositor_fill_checker_xrgb = GST_DEBUG_FUNCPTR (fill_checker_xrgb_c);
+ gst_compositor_fill_checker_yuy2 = GST_DEBUG_FUNCPTR (fill_checker_yuy2_c);
+ gst_compositor_fill_checker_uyvy = GST_DEBUG_FUNCPTR (fill_checker_uyvy_c);
- gst_compositor_fill_color_argb = fill_color_argb;
- gst_compositor_fill_color_bgra = fill_color_bgra;
- gst_compositor_fill_color_abgr = fill_color_abgr;
- gst_compositor_fill_color_rgba = fill_color_rgba;
- gst_compositor_fill_color_ayuv = fill_color_ayuv;
- gst_compositor_fill_color_i420 = fill_color_i420;
- gst_compositor_fill_color_yv12 = fill_color_yv12;
- gst_compositor_fill_color_nv12 = fill_color_nv12;
- gst_compositor_fill_color_y444 = fill_color_y444;
- gst_compositor_fill_color_y42b = fill_color_y42b;
- gst_compositor_fill_color_y41b = fill_color_y41b;
- gst_compositor_fill_color_rgb = fill_color_rgb_c;
- gst_compositor_fill_color_bgr = fill_color_bgr_c;
- gst_compositor_fill_color_xrgb = fill_color_xrgb;
- gst_compositor_fill_color_xbgr = fill_color_xbgr;
- gst_compositor_fill_color_rgbx = fill_color_rgbx;
- gst_compositor_fill_color_bgrx = fill_color_bgrx;
- gst_compositor_fill_color_yuy2 = fill_color_yuy2;
- gst_compositor_fill_color_yvyu = fill_color_yvyu;
- gst_compositor_fill_color_uyvy = fill_color_uyvy;
+ gst_compositor_fill_color_argb = GST_DEBUG_FUNCPTR (fill_color_argb);
+ gst_compositor_fill_color_bgra = GST_DEBUG_FUNCPTR (fill_color_bgra);
+ gst_compositor_fill_color_abgr = GST_DEBUG_FUNCPTR (fill_color_abgr);
+ gst_compositor_fill_color_rgba = GST_DEBUG_FUNCPTR (fill_color_rgba);
+ gst_compositor_fill_color_ayuv = GST_DEBUG_FUNCPTR (fill_color_ayuv);
+ gst_compositor_fill_color_i420 = GST_DEBUG_FUNCPTR (fill_color_i420);
+ gst_compositor_fill_color_yv12 = GST_DEBUG_FUNCPTR (fill_color_yv12);
+ gst_compositor_fill_color_nv12 = GST_DEBUG_FUNCPTR (fill_color_nv12);
+ gst_compositor_fill_color_y444 = GST_DEBUG_FUNCPTR (fill_color_y444);
+ gst_compositor_fill_color_y42b = GST_DEBUG_FUNCPTR (fill_color_y42b);
+ gst_compositor_fill_color_y41b = GST_DEBUG_FUNCPTR (fill_color_y41b);
+ gst_compositor_fill_color_rgb = GST_DEBUG_FUNCPTR (fill_color_rgb_c);
+ gst_compositor_fill_color_bgr = GST_DEBUG_FUNCPTR (fill_color_bgr_c);
+ gst_compositor_fill_color_xrgb = GST_DEBUG_FUNCPTR (fill_color_xrgb);
+ gst_compositor_fill_color_xbgr = GST_DEBUG_FUNCPTR (fill_color_xbgr);
+ gst_compositor_fill_color_rgbx = GST_DEBUG_FUNCPTR (fill_color_rgbx);
+ gst_compositor_fill_color_bgrx = GST_DEBUG_FUNCPTR (fill_color_bgrx);
+ gst_compositor_fill_color_yuy2 = GST_DEBUG_FUNCPTR (fill_color_yuy2);
+ gst_compositor_fill_color_yvyu = GST_DEBUG_FUNCPTR (fill_color_yvyu);
+ gst_compositor_fill_color_uyvy = GST_DEBUG_FUNCPTR (fill_color_uyvy);
}
diff --git a/gst/compositor/blend.h b/gst/compositor/blend.h
index 1cc127c4c..34d52306a 100644
--- a/gst/compositor/blend.h
+++ b/gst/compositor/blend.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
@@ -23,7 +23,21 @@
#include <gst/gst.h>
#include <gst/video/video.h>
-typedef void (*BlendFunction) (GstVideoFrame *srcframe, gint xpos, gint ypos, gdouble src_alpha, GstVideoFrame * destframe);
+/**
+ * GstCompositorBlendMode:
+ * @COMPOSITOR_BLEND_MODE_NORMAL: Normal blending
+ * @COMPOSITOR_BLEND_MODE_ADDITIVE: Alphas are simply added,
+ *
+ * The different modes compositor can use for blending.
+ */
+typedef enum
+{
+ COMPOSITOR_BLEND_MODE_NORMAL,
+ COMPOSITOR_BLEND_MODE_ADDITIVE,
+} GstCompositorBlendMode;
+
+typedef void (*BlendFunction) (GstVideoFrame *srcframe, gint xpos, gint ypos, gdouble src_alpha, GstVideoFrame * destframe,
+ GstCompositorBlendMode mode);
typedef void (*FillCheckerFunction) (GstVideoFrame * frame);
typedef void (*FillColorFunction) (GstVideoFrame * frame, gint c1, gint c2, gint c3);
@@ -32,10 +46,16 @@ extern BlendFunction gst_compositor_blend_bgra;
#define gst_compositor_blend_ayuv gst_compositor_blend_argb
#define gst_compositor_blend_abgr gst_compositor_blend_argb
#define gst_compositor_blend_rgba gst_compositor_blend_bgra
+#define gst_compositor_blend_ayuv_addition gst_compositor_blend_argb_addition
+#define gst_compositor_blend_abgr_addition gst_compositor_blend_argb_addition
+#define gst_compositor_blend_rgba_addition gst_compositor_blend_bgra_addition
+
+
extern BlendFunction gst_compositor_overlay_argb;
extern BlendFunction gst_compositor_overlay_bgra;
#define gst_compositor_overlay_ayuv gst_compositor_overlay_argb
#define gst_compositor_overlay_abgr gst_compositor_overlay_argb
+#define gst_compositor_overlay_abgr gst_compositor_overlay_argb
#define gst_compositor_overlay_rgba gst_compositor_overlay_bgra
extern BlendFunction gst_compositor_blend_i420;
#define gst_compositor_blend_yv12 gst_compositor_blend_i420
diff --git a/gst/compositor/compositor.c b/gst/compositor/compositor.c
index 23dc20cda..dceca349c 100644
--- a/gst/compositor/compositor.c
+++ b/gst/compositor/compositor.c
@@ -125,6 +125,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
#define DEFAULT_PAD_WIDTH 0
#define DEFAULT_PAD_HEIGHT 0
#define DEFAULT_PAD_ALPHA 1.0
+#define DEFAULT_PAD_CROSSFADE_RATIO -1.0
enum
{
PROP_PAD_0,
@@ -132,7 +133,8 @@ enum
PROP_PAD_YPOS,
PROP_PAD_WIDTH,
PROP_PAD_HEIGHT,
- PROP_PAD_ALPHA
+ PROP_PAD_ALPHA,
+ PROP_PAD_CROSSFADE_RATIO,
};
G_DEFINE_TYPE (GstCompositorPad, gst_compositor_pad,
@@ -160,6 +162,9 @@ gst_compositor_pad_get_property (GObject * object, guint prop_id,
case PROP_PAD_ALPHA:
g_value_set_double (value, pad->alpha);
break;
+ case PROP_PAD_CROSSFADE_RATIO:
+ g_value_set_double (value, pad->crossfade);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -188,6 +193,10 @@ gst_compositor_pad_set_property (GObject * object, guint prop_id,
case PROP_PAD_ALPHA:
pad->alpha = g_value_get_double (value);
break;
+ case PROP_PAD_CROSSFADE_RATIO:
+ pad->crossfade = g_value_get_double (value);
+ GST_VIDEO_AGGREGATOR_PAD (pad)->ABI.needs_alpha = pad->crossfade >= 0.0f;
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -475,11 +484,20 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
}
GST_OBJECT_LOCK (vagg);
+ /* Check if we are crossfading the pad one way or another */
+ l = g_list_find (GST_ELEMENT (vagg)->sinkpads, pad);
+ if ((l->prev && GST_COMPOSITOR_PAD (l->prev->data)->crossfade >= 0.0) ||
+ (GST_COMPOSITOR_PAD (pad)->crossfade >= 0.0)) {
+ GST_DEBUG_OBJECT (pad, "Is being crossfaded with previous pad");
+ l = NULL;
+ } else {
+ l = l->next;
+ }
+
/* Check if this frame is obscured by a higher-zorder frame
* TODO: Also skip a frame if it's obscured by a combination of
* higher-zorder frames */
- for (l = g_list_find (GST_ELEMENT (vagg)->sinkpads, pad)->next; l;
- l = l->next) {
+ for (; l; l = l->next) {
GstVideoRectangle frame2_rect;
GstVideoAggregatorPad *pad2 = l->data;
GstCompositorPad *cpad2 = GST_COMPOSITOR_PAD (pad2);
@@ -621,6 +639,12 @@ gst_compositor_pad_class_init (GstCompositorPadClass * klass)
g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
DEFAULT_PAD_ALPHA,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PAD_CROSSFADE_RATIO,
+ g_param_spec_double ("crossfade-ratio", "Crossfade ratio",
+ "The crossfade ratio to use while crossfading with the following pad."
+ "A value inferior to 0 means no crossfading.",
+ -1.0, 1.0, DEFAULT_PAD_CROSSFADE_RATIO,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
vaggpadclass->set_info = GST_DEBUG_FUNCPTR (gst_compositor_pad_set_info);
vaggpadclass->prepare_frame =
@@ -635,6 +659,7 @@ gst_compositor_pad_init (GstCompositorPad * compo_pad)
compo_pad->xpos = DEFAULT_PAD_XPOS;
compo_pad->ypos = DEFAULT_PAD_YPOS;
compo_pad->alpha = DEFAULT_PAD_ALPHA;
+ compo_pad->crossfade = DEFAULT_PAD_CROSSFADE_RATIO;
}
@@ -643,7 +668,7 @@ gst_compositor_pad_init (GstCompositorPad * compo_pad)
enum
{
PROP_0,
- PROP_BACKGROUND
+ PROP_BACKGROUND,
};
#define GST_TYPE_COMPOSITOR_BACKGROUND (gst_compositor_background_get_type())
@@ -963,6 +988,124 @@ _negotiated_caps (GstAggregator * agg, GstCaps * caps)
return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
}
+/* Fills frame with transparent pixels if @nframe is NULL otherwise copy @frame
+ * properties and fill @nframes with transparent pixels */
+static GstFlowReturn
+gst_compositor_fill_transparent (GstCompositor * self, GstVideoFrame * frame,
+ GstVideoFrame * nframe)
+{
+ guint plane, num_planes, height, i;
+
+ if (nframe) {
+ GstBuffer *cbuffer = gst_buffer_copy_deep (frame->buffer);
+
+ if (!gst_video_frame_map (nframe, &frame->info, cbuffer, GST_MAP_WRITE)) {
+ GST_WARNING_OBJECT (self, "Could not map output buffer");
+ return GST_FLOW_ERROR;
+ }
+ } else {
+ nframe = frame;
+ }
+
+ num_planes = GST_VIDEO_FRAME_N_PLANES (nframe);
+ for (plane = 0; plane < num_planes; ++plane) {
+ guint8 *pdata;
+ gsize rowsize, plane_stride;
+
+ pdata = GST_VIDEO_FRAME_PLANE_DATA (nframe, plane);
+ plane_stride = GST_VIDEO_FRAME_PLANE_STRIDE (nframe, plane);
+ rowsize = GST_VIDEO_FRAME_COMP_WIDTH (nframe, plane)
+ * GST_VIDEO_FRAME_COMP_PSTRIDE (nframe, plane);
+ height = GST_VIDEO_FRAME_COMP_HEIGHT (nframe, plane);
+ for (i = 0; i < height; ++i) {
+ memset (pdata, 0, rowsize);
+ pdata += plane_stride;
+ }
+ }
+
+ return GST_FLOW_OK;
+}
+
+/* WITH GST_OBJECT_LOCK !!
+ * Returns: %TRUE if outframe is allready ready to be used as we are using
+ * a transparent background and all pads have already been crossfaded
+ * %FALSE otherwise
+ */
+static gboolean
+gst_compositor_crossfade_frames (GstCompositor * self, GstVideoFrame * outframe)
+{
+ GList *l;
+ gboolean all_crossfading = FALSE;
+ GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (self);
+
+ if (self->background == COMPOSITOR_BACKGROUND_TRANSPARENT) {
+
+ all_crossfading = TRUE;
+ for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next) {
+ GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (l->data);
+
+ if (compo_pad->crossfade < 0.0 && l->next &&
+ GST_COMPOSITOR_PAD (l->next->data)->crossfade < 0) {
+ all_crossfading = FALSE;
+
+ break;
+ }
+ }
+ }
+
+ for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next) {
+ GstVideoAggregatorPad *pad = l->data;
+ GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad);
+
+ if (compo_pad->crossfade >= 0.0f && pad->aggregated_frame) {
+ gfloat alpha = compo_pad->crossfade * compo_pad->alpha;
+ GstVideoAggregatorPad *npad = l->next ? l->next->data : NULL;
+ GstVideoFrame *nframe;
+
+ if (!all_crossfading) {
+ nframe = g_slice_new0 (GstVideoFrame);
+ gst_compositor_fill_transparent (self, outframe, nframe);
+ } else {
+ nframe = outframe;
+ }
+
+ self->overlay (pad->aggregated_frame,
+ compo_pad->crossfaded ? 0 : compo_pad->xpos,
+ compo_pad->crossfaded ? 0 : compo_pad->ypos,
+ alpha, nframe, COMPOSITOR_BLEND_MODE_ADDITIVE);
+
+ if (npad && npad->aggregated_frame) {
+ GstCompositorPad *next_compo_pad = GST_COMPOSITOR_PAD (npad);
+
+ alpha = (1.0 - compo_pad->crossfade) * next_compo_pad->alpha;
+ self->overlay (npad->aggregated_frame, next_compo_pad->xpos,
+ next_compo_pad->ypos, alpha, nframe,
+ COMPOSITOR_BLEND_MODE_ADDITIVE);
+
+ /* Replace frame with current frame */
+ gst_compositor_pad_clean_frame (npad, vagg);
+ npad->aggregated_frame = !all_crossfading ? nframe : NULL;
+ next_compo_pad->crossfaded = TRUE;
+
+ /* Frame is now consumed, clean it up */
+ gst_compositor_pad_clean_frame (pad, vagg);
+ pad->aggregated_frame = NULL;
+ } else {
+ GST_LOG_OBJECT (self, "Simply fading out as no following pad found");
+ gst_compositor_pad_clean_frame (pad, vagg);
+ pad->aggregated_frame = !all_crossfading ? nframe : NULL;
+ compo_pad->crossfaded = TRUE;
+ }
+ }
+ }
+
+ if (all_crossfading)
+ for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
+ GST_COMPOSITOR_PAD (l->data)->crossfaded = FALSE;
+
+ return all_crossfading;
+}
+
static GstFlowReturn
gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
{
@@ -992,39 +1135,26 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
self->fill_color (outframe, 240, 128, 128);
break;
case COMPOSITOR_BACKGROUND_TRANSPARENT:
- {
- guint i, plane, num_planes, height;
-
- num_planes = GST_VIDEO_FRAME_N_PLANES (outframe);
- for (plane = 0; plane < num_planes; ++plane) {
- guint8 *pdata;
- gsize rowsize, plane_stride;
-
- pdata = GST_VIDEO_FRAME_PLANE_DATA (outframe, plane);
- plane_stride = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, plane);
- rowsize = GST_VIDEO_FRAME_COMP_WIDTH (outframe, plane)
- * GST_VIDEO_FRAME_COMP_PSTRIDE (outframe, plane);
- height = GST_VIDEO_FRAME_COMP_HEIGHT (outframe, plane);
- for (i = 0; i < height; ++i) {
- memset (pdata, 0, rowsize);
- pdata += plane_stride;
- }
- }
-
+ gst_compositor_fill_transparent (self, outframe, NULL);
/* use overlay to keep background transparent */
composite = self->overlay;
break;
- }
}
GST_OBJECT_LOCK (vagg);
- for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
- GstVideoAggregatorPad *pad = l->data;
- GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad);
-
- if (pad->aggregated_frame != NULL) {
- composite (pad->aggregated_frame, compo_pad->xpos, compo_pad->ypos,
- compo_pad->alpha, outframe);
+ /* First mix the crossfade frames as required */
+ if (!gst_compositor_crossfade_frames (self, outframe)) {
+ for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
+ GstVideoAggregatorPad *pad = l->data;
+ GstCompositorPad *compo_pad = GST_COMPOSITOR_PAD (pad);
+
+ if (pad->aggregated_frame != NULL) {
+ composite (pad->aggregated_frame,
+ compo_pad->crossfaded ? 0 : compo_pad->xpos,
+ compo_pad->crossfaded ? 0 : compo_pad->ypos, compo_pad->alpha,
+ outframe, COMPOSITOR_BLEND_MODE_NORMAL);
+ compo_pad->crossfaded = FALSE;
+ }
}
}
GST_OBJECT_UNLOCK (vagg);
@@ -1112,8 +1242,8 @@ gst_compositor_class_init (GstCompositorClass * klass)
static void
gst_compositor_init (GstCompositor * self)
{
- self->background = DEFAULT_BACKGROUND;
/* initialize variables */
+ self->background = DEFAULT_BACKGROUND;
}
/* Element registration */
diff --git a/gst/compositor/compositor.h b/gst/compositor/compositor.h
index a6b4d9fce..d8cefa3d2 100644
--- a/gst/compositor/compositor.h
+++ b/gst/compositor/compositor.h
@@ -17,7 +17,7 @@
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
-
+
#ifndef __GST_COMPOSITOR_H__
#define __GST_COMPOSITOR_H__
@@ -57,8 +57,7 @@ typedef enum
COMPOSITOR_BACKGROUND_BLACK,
COMPOSITOR_BACKGROUND_WHITE,
COMPOSITOR_BACKGROUND_TRANSPARENT,
-}
-GstCompositorBackground;
+} GstCompositorBackground;
/**
* GstCompositor:
diff --git a/gst/compositor/compositororc.orc b/gst/compositor/compositororc.orc
index 234ec2112..66c4dcc73 100644
--- a/gst/compositor/compositororc.orc
+++ b/gst/compositor/compositororc.orc
@@ -98,7 +98,6 @@ x4 convwb t, d_wide
orl t, t, a_alpha
storel d, t
-
.function compositor_orc_overlay_argb
.flags 2d
.dest 4 d guint8
@@ -159,6 +158,76 @@ andl a, a, a_alpha
orl t, t, a
storel d, t
+
+.function compositor_orc_overlay_argb_addition
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 2 tw
+.temp 1 tb
+.temp 8 alpha_s
+.temp 8 alpha_s_inv
+.temp 8 alpha_factor
+.temp 8 alpha_d
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.const 4 xfs 0xffffffff
+.const 4 a_alpha 0x000000ff
+.const 4 a_alpha_inv 0xffffff00
+
+# calc source alpha as alpha_s = alpha_s * alpha / 255
+loadl t, s
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_s, a
+x4 mullw alpha_s, alpha_s, alpha
+x4 div255w alpha_s, alpha_s
+x4 convubw s_wide, t
+x4 mullw s_wide, s_wide, alpha_s
+
+# calc destination alpha as alpha_factor = (255-alpha_s) * alpha_factor / factor
+loadpl a, xfs
+x4 convubw alpha_s_inv, a
+x4 subw alpha_s_inv, alpha_s_inv, alpha_s
+loadl t, d
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_factor, a
+x4 mullw alpha_factor, alpha_factor, alpha_s_inv
+x4 div255w alpha_factor, alpha_factor
+x4 convubw d_wide, t
+x4 mullw d_wide, d_wide, alpha_factor
+
+# calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_factor*(255-alpha_s)/255
+x4 addw d_wide, d_wide, s_wide
+
+# calc the alpha factor alpha_factor = alpha_s + alpha_factor * (255-alpha_s)/255
+x4 addw alpha_factor, alpha_factor, alpha_s
+
+# now normalize the pix_d by the final alpha to make it associative
+x4 divluw, d_wide, d_wide, alpha_factor
+
+# calc the final global alpha_d = alpha_d + (alpha_s * (alpha / 255))
+loadl t, d
+convlw tw, t
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_d, a
+x4 addw alpha_d, alpha_d, alpha_s
+
+# pack the new alpha into the correct spot
+x4 convwb t, d_wide
+andl t, t, a_alpha_inv
+x4 convwb a, alpha_d
+andl a, a, a_alpha
+orl t, t, a
+storel d, t
+
.function compositor_orc_overlay_bgra
.flags 2d
.dest 4 d guint8
@@ -221,3 +290,76 @@ x4 convwb a, alpha_d
andl a, a, a_alpha
orl t, t, a
storel d, t
+
+.function compositor_orc_overlay_bgra_addition
+.flags 2d
+.dest 4 d guint8
+.source 4 s guint8
+.param 2 alpha
+.temp 4 t
+.temp 4 t2
+.temp 2 tw
+.temp 1 tb
+.temp 8 alpha_s
+.temp 8 alpha_s_inv
+.temp 8 alpha_factor
+.temp 8 alpha_d
+.temp 4 a
+.temp 8 d_wide
+.temp 8 s_wide
+.const 4 xfs 0xffffffff
+.const 4 a_alpha 0xff000000
+.const 4 a_alpha_inv 0x00ffffff
+
+# calc source alpha as alpha_s = alpha_s * alpha / 255
+loadl t, s
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_s, a
+x4 mullw alpha_s, alpha_s, alpha
+x4 div255w alpha_s, alpha_s
+x4 convubw s_wide, t
+x4 mullw s_wide, s_wide, alpha_s
+
+# calc destination alpha as alpha_factor = (255-alpha_s) * alpha_factor / 255
+loadpl a, xfs
+x4 convubw alpha_s_inv, a
+x4 subw alpha_s_inv, alpha_s_inv, alpha_s
+loadl t, d
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_factor, a
+x4 mullw alpha_factor, alpha_factor, alpha_s_inv
+x4 div255w alpha_factor, alpha_factor
+x4 convubw d_wide, t
+x4 mullw d_wide, d_wide, alpha_factor
+
+# calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_factor*(255-alpha_s)/255
+x4 addw d_wide, d_wide, s_wide
+
+# calc the final destination alpha_factor = alpha_s + alpha_factor * (255-alpha_s)/255
+x4 addw alpha_factor, alpha_factor, alpha_s
+
+# now normalize the pix_d by the final alpha to make it associative
+x4 divluw, d_wide, d_wide, alpha_factor
+
+# calc the final global alpha_d = alpha_d + (alpha_s * (alpha / 255))
+loadl t, d
+shrul t2, t, 24
+convlw tw, t2
+convwb tb, tw
+splatbl a, tb
+x4 convubw alpha_d, a
+x4 addw alpha_d, alpha_d, alpha_s
+
+# pack the new alpha into the correct spot
+x4 convwb t, d_wide
+andl t, t, a_alpha_inv
+x4 convwb a, alpha_d
+andl a, a, a_alpha
+orl t, t, a
+storel d, t
diff --git a/gst/compositor/compositorpad.h b/gst/compositor/compositorpad.h
index cb6f7c735..1c2a271a8 100644
--- a/gst/compositor/compositorpad.h
+++ b/gst/compositor/compositorpad.h
@@ -52,10 +52,13 @@ struct _GstCompositorPad
gint xpos, ypos;
gint width, height;
gdouble alpha;
+ gdouble crossfade;
GstVideoConverter *convert;
GstVideoInfo conversion_info;
GstBuffer *converted_buffer;
+
+ gboolean crossfaded;
};
struct _GstCompositorPadClass