mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 00:36:51 +00:00
56d47f641f
For formats which we don't have fast-path implementation, compositor will convert it to common unpack formats (AYUV, ARGB, AYUV64 and ARGB64) then blending will happen using the intermediate formats. Finally blended image will be converted back to the selected output format if required. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1486>
2125 lines
74 KiB
C
2125 lines
74 KiB
C
/*
|
|
* 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>
|
|
|
|
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, VUYA, ARGB and BGRA */
|
|
#define BLEND_A32(name, method, LOOP) \
|
|
static void \
|
|
method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
|
|
gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
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 * 255), 0, 255); \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (s_alpha == 0)) \
|
|
return; \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
/* adjust src pointers for negative sizes */ \
|
|
if (xpos < 0) { \
|
|
src += -xpos * 4; \
|
|
src_width -= -xpos; \
|
|
xpos = 0; \
|
|
} \
|
|
if (ypos < dst_y_start) { \
|
|
src += (dst_y_start - ypos) * src_stride; \
|
|
src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
/* 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 > dst_y_end) { \
|
|
src_height = dst_y_end - 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, \
|
|
mode); \
|
|
} \
|
|
}
|
|
|
|
#define OVERLAY_A32_LOOP(name) \
|
|
static inline void \
|
|
_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); \
|
|
switch (mode) { \
|
|
case COMPOSITOR_BLEND_MODE_SOURCE:\
|
|
if (s_alpha == 255) { \
|
|
guint y; \
|
|
for (y = 0; y < src_height; y++) { \
|
|
memcpy (dest, src, 4 * src_width); \
|
|
dest += dest_stride; \
|
|
src += src_stride; \
|
|
} \
|
|
} else { \
|
|
compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
} \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_OVER:\
|
|
compositor_orc_overlay_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_ADD:\
|
|
compositor_orc_overlay_##name##_addition (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
}\
|
|
}
|
|
|
|
#define BLEND_A32_LOOP(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); \
|
|
switch (mode) { \
|
|
case COMPOSITOR_BLEND_MODE_SOURCE:\
|
|
if (s_alpha == 255) { \
|
|
guint y; \
|
|
for (y = 0; y < src_height; y++) { \
|
|
memcpy (dest, src, 4 * src_width); \
|
|
dest += dest_stride; \
|
|
src += src_stride; \
|
|
} \
|
|
} else { \
|
|
compositor_orc_source_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
} \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_OVER:\
|
|
case COMPOSITOR_BLEND_MODE_ADD:\
|
|
/* both modes are the same for opaque background */ \
|
|
compositor_orc_blend_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
}\
|
|
}
|
|
|
|
OVERLAY_A32_LOOP (argb);
|
|
OVERLAY_A32_LOOP (bgra);
|
|
BLEND_A32_LOOP (argb);
|
|
BLEND_A32_LOOP (bgra);
|
|
|
|
#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, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
gint val; \
|
|
static const gint tab[] = { 80, 160, 80, 160 }; \
|
|
gint width, stride; \
|
|
guint8 *dest; \
|
|
\
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
\
|
|
dest += y_start * stride; \
|
|
if (!RGB) { \
|
|
for (i = y_start; i < y_end; 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 = y_start; i < y_end; 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);
|
|
A32_CHECKER_C (vuya, FALSE, 3, 2, 1, 0);
|
|
|
|
#define A32_COLOR(name, A, C1, C2, C3) \
|
|
static void \
|
|
fill_color_##name (GstVideoFrame * frame, guint y_start, guint y_end, gint c1, gint c2, gint c3) \
|
|
{ \
|
|
guint32 val; \
|
|
gint stride; \
|
|
guint8 *dest; \
|
|
\
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
\
|
|
dest += y_start * stride; \
|
|
val = GUINT32_FROM_BE ((0xff << A) | (c1 << C1) | (c2 << C2) | (c3 << C3)); \
|
|
\
|
|
compositor_orc_splat_u32 ((guint32 *) dest, val, (y_end - y_start) * (stride / 4)); \
|
|
}
|
|
|
|
A32_COLOR (argb, 24, 16, 8, 0);
|
|
A32_COLOR (bgra, 0, 8, 16, 24);
|
|
A32_COLOR (abgr, 24, 0, 8, 16);
|
|
A32_COLOR (rgba, 0, 24, 16, 8);
|
|
A32_COLOR (ayuv, 24, 16, 8, 0);
|
|
A32_COLOR (vuya, 0, 8, 16, 24);
|
|
|
|
/* Y444, Y42B, I420, YV12, Y41B */
|
|
#define PLANAR_YUV_BLEND(format_name,x_round,y_round,MEMCPY,BLENDLOOP,n_bits) \
|
|
inline static void \
|
|
_blend_##format_name (const guint8 * src, guint8 * dest, \
|
|
gint src_stride, gint dest_stride, gint pstride, gint src_width, gint src_height, \
|
|
gdouble src_alpha, GstCompositorBlendMode mode) \
|
|
{ \
|
|
gint i; \
|
|
gint b_alpha; \
|
|
gint range; \
|
|
\
|
|
/* in source mode we just have to copy over things */ \
|
|
if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
|
|
src_alpha = 1.0; \
|
|
} \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (src_alpha == 0.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 0.0)"); \
|
|
return; \
|
|
} \
|
|
\
|
|
/* If it's completely opaque, we do a fast copy */ \
|
|
if (G_UNLIKELY (src_alpha == 1.0)) { \
|
|
gint width_in_bytes = src_width * pstride; \
|
|
GST_LOG ("Fast copy (alpha == 1.0)"); \
|
|
for (i = 0; i < src_height; i++) { \
|
|
MEMCPY (dest, src, width_in_bytes); \
|
|
src += src_stride; \
|
|
dest += dest_stride; \
|
|
} \
|
|
return; \
|
|
} \
|
|
\
|
|
range = (1 << n_bits) - 1; \
|
|
b_alpha = CLAMP ((gint) (src_alpha * range), 0, range); \
|
|
\
|
|
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, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
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; \
|
|
gint pstride; \
|
|
\
|
|
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); \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
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 < dst_y_start) { \
|
|
yoffset = dst_y_start - ypos; \
|
|
b_src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
/* 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 + b_src_width > dest_width) { \
|
|
b_src_width = dest_width - xpos; \
|
|
} \
|
|
if (ypos + b_src_height > dst_y_end) { \
|
|
b_src_height = dst_y_end - 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); \
|
|
pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 0); \
|
|
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 * pstride + comp_yoffset * src_comp_rowstride, \
|
|
b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
|
|
src_comp_rowstride, \
|
|
dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
|
|
src_alpha, mode); \
|
|
\
|
|
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); \
|
|
pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 1); \
|
|
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xpos); \
|
|
comp_ypos = (ypos == 0) ? 0 : ypos >> info->h_sub[1]; \
|
|
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
|
|
comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[1]; \
|
|
_blend_##format_name (b_src + comp_xoffset * pstride + comp_yoffset * src_comp_rowstride, \
|
|
b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
|
|
src_comp_rowstride, \
|
|
dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
|
|
src_alpha, mode); \
|
|
\
|
|
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); \
|
|
pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (info, 2); \
|
|
comp_xpos = (xpos == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xpos); \
|
|
comp_ypos = (ypos == 0) ? 0 : ypos >> info->h_sub[2]; \
|
|
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 2, xoffset); \
|
|
comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[2]; \
|
|
_blend_##format_name (b_src + comp_xoffset * pstride + comp_yoffset * src_comp_rowstride, \
|
|
b_dest + comp_xpos * pstride + comp_ypos * dest_comp_rowstride, \
|
|
src_comp_rowstride, \
|
|
dest_comp_rowstride, pstride, src_comp_width, src_comp_height, \
|
|
src_alpha, mode); \
|
|
}
|
|
|
|
#define PLANAR_YUV_FILL_CHECKER(format_name, format_enum, MEMSET) \
|
|
static void \
|
|
fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
static const int tab[] = { 80, 160, 80, 160 }; \
|
|
guint8 *p; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
for (i = 0; i < comp_height; i++) { \
|
|
for (j = 0; j < comp_width; j++) { \
|
|
*p++ = tab[(((i + y_start) & 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_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
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_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
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, \
|
|
guint y_start, guint y_end, gint colY, gint colU, gint colV) \
|
|
{ \
|
|
guint8 *p; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
gint i; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
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_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
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_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
for (i = 0; i < comp_height; i++) { \
|
|
MEMSET (p, colV, comp_width); \
|
|
p += rowstride; \
|
|
} \
|
|
}
|
|
|
|
#define PLANAR_YUV_HIGH_FILL_CHECKER(format_name, nbits, endian, MEMSET) \
|
|
static void \
|
|
fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
static const int tab[] = { 80 << (nbits - 8), 160 << (nbits - 8), 80 << (nbits - 8), 160 << (nbits - 8),}; \
|
|
guint8 *p; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
gint pstride; \
|
|
gint uv; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
for (i = 0; i < comp_height; i++) { \
|
|
for (j = 0; j < comp_width; j++) { \
|
|
GST_WRITE_UINT16_##endian (p, tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]); \
|
|
p += pstride; \
|
|
} \
|
|
p += rowstride - comp_width * pstride; \
|
|
} \
|
|
\
|
|
uv = GUINT16_TO_##endian (1 << (nbits - 1)); \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
p += comp_yoffset * rowstride; \
|
|
MEMSET (p, rowstride, uv, comp_width, comp_height); \
|
|
\
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
|
|
pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
|
|
p += comp_yoffset * rowstride; \
|
|
MEMSET (p, rowstride, uv, comp_width, comp_height); \
|
|
}
|
|
|
|
#define PLANAR_YUV_HIGH_FILL_COLOR(format_name,endian,MEMSET) \
|
|
static void \
|
|
fill_color_##format_name (GstVideoFrame * frame, \
|
|
guint y_start, guint y_end, gint colY, gint colU, gint colV) \
|
|
{ \
|
|
guint8 *p; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
p += comp_yoffset * rowstride; \
|
|
MEMSET (p, rowstride, GUINT16_TO_##endian (colY), comp_width, comp_height); \
|
|
\
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
p += comp_yoffset * rowstride; \
|
|
MEMSET (p, rowstride, GUINT16_TO_##endian (colU), comp_width, comp_height); \
|
|
\
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 2); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 2, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 2); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[2]; \
|
|
p += comp_yoffset * rowstride; \
|
|
MEMSET (p, rowstride, GUINT16_TO_##endian (colV), comp_width, comp_height); \
|
|
}
|
|
|
|
#define GST_ROUND_UP_1(x) (x)
|
|
|
|
PLANAR_YUV_BLEND (i420, GST_ROUND_UP_2,
|
|
GST_ROUND_UP_2, memcpy, compositor_orc_blend_u8, 8);
|
|
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_ROUND_UP_1,
|
|
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
|
|
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_ROUND_UP_2,
|
|
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
|
|
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_ROUND_UP_4,
|
|
GST_ROUND_UP_1, memcpy, compositor_orc_blend_u8, 8);
|
|
PLANAR_YUV_FILL_CHECKER (y41b, GST_VIDEO_FORMAT_Y41B, memset);
|
|
PLANAR_YUV_FILL_COLOR (y41b, GST_VIDEO_FORMAT_Y41B, memset);
|
|
|
|
#define BLEND_HIGH(format_name) \
|
|
compositor_orc_blend_##format_name
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
PLANAR_YUV_BLEND (i420_10le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
PLANAR_YUV_BLEND (i420_10be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
|
|
PLANAR_YUV_BLEND (i420_12le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
PLANAR_YUV_BLEND (i420_12be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
|
|
PLANAR_YUV_BLEND (i422_10le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
PLANAR_YUV_BLEND (i422_10be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
|
|
PLANAR_YUV_BLEND (i422_12le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
PLANAR_YUV_BLEND (i422_12be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
|
|
PLANAR_YUV_BLEND (y444_10le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
PLANAR_YUV_BLEND (y444_10be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
|
|
PLANAR_YUV_BLEND (y444_12le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
PLANAR_YUV_BLEND (y444_12be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
|
|
PLANAR_YUV_BLEND (y444_16le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u16), 16);
|
|
PLANAR_YUV_BLEND (y444_16be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u16_swap), 16);
|
|
#else /* G_BYTE_ORDER == G_LITTLE_ENDIAN */
|
|
PLANAR_YUV_BLEND (i420_10le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
PLANAR_YUV_BLEND (i420_10be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
|
|
PLANAR_YUV_BLEND (i420_12le, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
PLANAR_YUV_BLEND (i420_12be, GST_ROUND_UP_2, GST_ROUND_UP_2, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
|
|
PLANAR_YUV_BLEND (i422_10le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
PLANAR_YUV_BLEND (i422_10be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
|
|
PLANAR_YUV_BLEND (i422_12le, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
PLANAR_YUV_BLEND (i422_12be, GST_ROUND_UP_2, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
|
|
PLANAR_YUV_BLEND (y444_10le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10_swap), 10);
|
|
PLANAR_YUV_BLEND (y444_10be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u10), 10);
|
|
|
|
PLANAR_YUV_BLEND (y444_12le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12_swap), 12);
|
|
PLANAR_YUV_BLEND (y444_12be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u12), 12);
|
|
|
|
PLANAR_YUV_BLEND (y444_16le, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u16_swap), 16);
|
|
PLANAR_YUV_BLEND (y444_16be, GST_ROUND_UP_1, GST_ROUND_UP_1, memcpy,
|
|
BLEND_HIGH (u16), 16);
|
|
#endif /* G_BYTE_ORDER == G_LITTLE_ENDIAN */
|
|
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (i420_10le, 10, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (i420_10le, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (i420_10be, 10, BE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (i420_10be, BE, compositor_orc_memset_u16_2d);
|
|
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (i420_12le, 12, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (i420_12le, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (i420_12be, 12, BE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (i420_12be, BE, compositor_orc_memset_u16_2d);
|
|
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (y444_16le, 16, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (y444_16le, LE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_CHECKER (y444_16be, 16, BE, compositor_orc_memset_u16_2d);
|
|
PLANAR_YUV_HIGH_FILL_COLOR (y444_16be, BE, compositor_orc_memset_u16_2d);
|
|
|
|
/* TODO: port to ORC */
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
static void
|
|
compositor_blend_argb64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0xffff000000000000;
|
|
const guint64 comp_mask_1 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_2 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_alpha = 0x000000000000ffff;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
|
|
src_comp[0] = (src_val & comp_mask_0) >> 48;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 32;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 16;
|
|
|
|
dst_comp[0] = (dst_val & comp_mask_0) >> 48;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 32;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 16;
|
|
|
|
src_alpha = src_val & comp_mask_alpha;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++) {
|
|
src_comp[k] *= src_alpha;
|
|
dst_comp[k] *= src_alpha_inv;
|
|
dst_comp[k] += src_comp[k];
|
|
dst_comp[k] /= G_MAXUINT16;
|
|
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
dst_val = (dst_comp[0] << 48) | (dst_comp[1] << 32) | (dst_comp[2] << 16)
|
|
| comp_mask_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_source_argb64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j;
|
|
const guint64 comp_mask_non_alpha = 0xffffffffffff0000;
|
|
const guint64 comp_mask_alpha = 0x000000000000ffff;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val;
|
|
guint64 src_alpha;
|
|
|
|
src_alpha = src_val & comp_mask_alpha;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
|
|
dst_val = (src_val & comp_mask_non_alpha) | src_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_overlay_argb64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0xffff000000000000;
|
|
const guint64 comp_mask_1 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_2 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_alpha = 0x000000000000ffff;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
guint64 dst_alpha;
|
|
|
|
src_comp[0] = (src_val & comp_mask_0) >> 48;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 32;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 16;
|
|
|
|
dst_comp[0] = (dst_val & comp_mask_0) >> 48;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 32;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 16;
|
|
|
|
/* calc source alpha as alpha_s = alpha_s * alpha / 255 */
|
|
src_alpha = src_val & comp_mask_alpha;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++)
|
|
src_comp[k] *= src_alpha;
|
|
|
|
/* calc destination alpha as alpha_d = (1.0 - alpha_s) * alpha_d / 1.0 */
|
|
dst_alpha = dst_val & comp_mask_alpha;
|
|
dst_alpha *= src_alpha_inv;
|
|
dst_alpha /= G_MAXUINT16;
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] *= dst_alpha;
|
|
|
|
/* calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_d*(255-alpha_s)/255 */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] += src_comp[k];
|
|
|
|
/* calc the final destination alpha_d = alpha_s + alpha_d * (255-alpha_s)/255 */
|
|
dst_alpha += src_alpha;
|
|
dst_alpha = CLAMP (dst_alpha, 0, G_MAXUINT16);
|
|
|
|
/* now normalize the pix_d by the final alpha to make it associative */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++) {
|
|
if (dst_alpha > 0)
|
|
dst_comp[k] /= dst_alpha;
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
dst_val = (dst_comp[0] << 48) | (dst_comp[1] << 32) | (dst_comp[2] << 16)
|
|
| dst_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_overlay_argb64_addition (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0xffff000000000000;
|
|
const guint64 comp_mask_1 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_2 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_alpha = 0x000000000000ffff;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
guint64 alpha_factor;
|
|
guint64 dst_alpha;
|
|
|
|
src_comp[0] = (src_val & comp_mask_0) >> 48;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 32;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 16;
|
|
|
|
dst_comp[0] = (dst_val & comp_mask_0) >> 48;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 32;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 16;
|
|
|
|
/* calc source alpha as alpha_s = alpha_s * alpha / 255 */
|
|
src_alpha = src_val & comp_mask_alpha;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++)
|
|
src_comp[k] *= src_alpha;
|
|
|
|
/* calc destination alpha as alpha_factor = (255-alpha_s) * alpha_factor / factor */
|
|
alpha_factor = dst_val & comp_mask_alpha;
|
|
alpha_factor *= src_alpha_inv;
|
|
alpha_factor /= G_MAXUINT16;
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] *= alpha_factor;
|
|
|
|
/* calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_factor*(255-alpha_s)/255 */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] += src_comp[k];
|
|
|
|
/* calc the alpha factor alpha_factor = alpha_s + alpha_factor * (255-alpha_s)/255 */
|
|
alpha_factor += src_alpha;
|
|
alpha_factor = CLAMP (alpha_factor, 0, G_MAXUINT16);
|
|
|
|
/* now normalize the pix_d by the final alpha to make it associative */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++) {
|
|
if (alpha_factor > 0)
|
|
dst_comp[k] /= alpha_factor;
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
/* calc the final global alpha_d = alpha_d + (alpha_s * (alpha / 255)) */
|
|
dst_alpha = dst_val & comp_mask_alpha;
|
|
dst_alpha += src_alpha;
|
|
dst_alpha = CLAMP (dst_alpha, 0, G_MAXUINT16);
|
|
|
|
dst_val = (dst_comp[0] << 48) | (dst_comp[1] << 32) | (dst_comp[2] << 16)
|
|
| dst_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
#else /* if G_BYTE_ORDER == G_LITTLE_ENDIAN */
|
|
static void
|
|
compositor_blend_bgra64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0x000000000000ffff;
|
|
const guint64 comp_mask_1 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_2 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_alpha = 0xffff000000000000;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
|
|
src_comp[0] = src_val & comp_mask_0;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 16;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 32;
|
|
|
|
dst_comp[0] = dst_val & comp_mask_0;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 16;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 32;
|
|
|
|
src_alpha = (src_val & comp_mask_alpha) >> 48;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++) {
|
|
src_comp[k] *= src_alpha;
|
|
dst_comp[k] *= src_alpha_inv;
|
|
dst_comp[k] += src_comp[k];
|
|
dst_comp[k] /= G_MAXUINT16;
|
|
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
dst_val = (dst_comp[0]) | (dst_comp[1] << 16) | (dst_comp[2] << 32)
|
|
| comp_mask_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_source_bgra64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j;
|
|
const guint64 comp_mask_non_alpha = 0x0000ffffffffffff;
|
|
const guint64 comp_mask_alpha = 0xffff000000000000;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val;
|
|
guint64 src_alpha;
|
|
|
|
src_alpha = (src_val & comp_mask_alpha) >> 48;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha <<= 48;
|
|
|
|
dst_val = (src_val & comp_mask_non_alpha) | src_alpha;
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_overlay_bgra64 (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0x000000000000ffff;
|
|
const guint64 comp_mask_1 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_2 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_alpha = 0xffff000000000000;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
guint64 dst_alpha;
|
|
|
|
src_comp[0] = src_val & comp_mask_0;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 16;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 32;
|
|
|
|
dst_comp[0] = dst_val & comp_mask_0;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 16;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 32;
|
|
|
|
/* calc source alpha as alpha_s = alpha_s * alpha / 255 */
|
|
src_alpha = (src_val & comp_mask_alpha) >> 48;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++)
|
|
src_comp[k] *= src_alpha;
|
|
/* calc destination alpha as alpha_d = (1.0 - alpha_s) * alpha_d / 1.0 */
|
|
dst_alpha = (dst_val & comp_mask_alpha) >> 48;
|
|
dst_alpha *= src_alpha_inv;
|
|
dst_alpha /= G_MAXUINT16;
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] *= dst_alpha;
|
|
|
|
/* calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_d*(255-alpha_s)/255 */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] += src_comp[k];
|
|
|
|
/* calc the final destination alpha_d = alpha_s + alpha_d * (255-alpha_s)/255 */
|
|
dst_alpha += src_alpha;
|
|
dst_alpha = CLAMP (dst_alpha, 0, G_MAXUINT16);
|
|
|
|
/* now normalize the pix_d by the final alpha to make it associative */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++) {
|
|
if (dst_alpha > 0)
|
|
dst_comp[k] /= dst_alpha;
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
dst_val = (dst_comp[0]) | (dst_comp[1] << 16) | (dst_comp[2] << 32)
|
|
| (dst_alpha << 48);
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
compositor_overlay_bgra64_addition (guint8 * ORC_RESTRICT d1, int d1_stride,
|
|
const guint8 * ORC_RESTRICT s1, int s1_stride, int p1, int n, int m)
|
|
{
|
|
gint i, j, k;
|
|
const guint64 comp_mask_0 = 0x000000000000ffff;
|
|
const guint64 comp_mask_1 = 0x00000000ffff0000;
|
|
const guint64 comp_mask_2 = 0x0000ffff00000000;
|
|
const guint64 comp_mask_alpha = 0xffff000000000000;
|
|
|
|
for (j = 0; j < m; j++) {
|
|
guint64 *dst;
|
|
guint64 *src;
|
|
|
|
dst = (guint64 *) (d1 + (d1_stride * j));
|
|
src = (guint64 *) (s1 + (s1_stride * j));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
guint64 src_val = src[i];
|
|
guint64 dst_val = dst[i];
|
|
guint64 src_comp[3];
|
|
guint64 dst_comp[3];
|
|
guint64 src_alpha;
|
|
guint64 src_alpha_inv;
|
|
guint64 alpha_factor;
|
|
guint64 dst_alpha;
|
|
|
|
src_comp[0] = src_val & comp_mask_0;
|
|
src_comp[1] = (src_val & comp_mask_1) >> 16;
|
|
src_comp[2] = (src_val & comp_mask_2) >> 32;
|
|
|
|
dst_comp[0] = dst_val & comp_mask_0;
|
|
dst_comp[1] = (dst_val & comp_mask_1) >> 16;
|
|
dst_comp[2] = (dst_val & comp_mask_2) >> 32;
|
|
|
|
/* calc source alpha as alpha_s = alpha_s * alpha / 255 */
|
|
src_alpha = (src_val & comp_mask_alpha) >> 48;
|
|
src_alpha *= p1;
|
|
src_alpha /= G_MAXUINT16;
|
|
src_alpha = CLAMP (src_alpha, 0, G_MAXUINT16);
|
|
src_alpha_inv = G_MAXUINT16 - src_alpha;
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (src_comp); k++)
|
|
src_comp[k] *= src_alpha;
|
|
|
|
/* calc destination alpha as alpha_factor = (255-alpha_s) * alpha_factor / factor */
|
|
alpha_factor = (dst_val & comp_mask_alpha) >> 48;
|
|
alpha_factor *= src_alpha_inv;
|
|
alpha_factor /= G_MAXUINT16;
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] *= alpha_factor;
|
|
|
|
/* calc final pixel as pix_d = pix_s*alpha_s + pix_d*alpha_factor*(255-alpha_s)/255 */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++)
|
|
dst_comp[k] += src_comp[k];
|
|
|
|
/* calc the alpha factor alpha_factor = alpha_s + alpha_factor * (255-alpha_s)/255 */
|
|
alpha_factor += src_alpha;
|
|
alpha_factor = CLAMP (alpha_factor, 0, G_MAXUINT16);
|
|
|
|
/* now normalize the pix_d by the final alpha to make it associative */
|
|
for (k = 0; k < G_N_ELEMENTS (dst_comp); k++) {
|
|
if (alpha_factor > 0)
|
|
dst_comp[k] /= alpha_factor;
|
|
dst_comp[k] = CLAMP (dst_comp[k], 0, G_MAXUINT16);
|
|
}
|
|
|
|
/* calc the final global alpha_d = alpha_d + (alpha_s * (alpha / 255)) */
|
|
dst_alpha = (dst_val & comp_mask_alpha) >> 48;
|
|
dst_alpha += src_alpha;
|
|
dst_alpha = CLAMP (dst_alpha, 0, G_MAXUINT16);
|
|
|
|
dst_val = (dst_comp[0]) | (dst_comp[1] << 16) | (dst_comp[2] << 32)
|
|
| (dst_alpha << 48);
|
|
dst[i] = dst_val;
|
|
}
|
|
}
|
|
}
|
|
#endif /* if G_BYTE_ORDER == G_LITTLE_ENDIAN */
|
|
|
|
/* for AYUV64, ARGB64 */
|
|
#define BLEND_A64(name, method, LOOP) \
|
|
static void \
|
|
method##_ ##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
|
|
gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
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 * G_MAXUINT16), 0, G_MAXUINT16); \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (s_alpha == 0)) \
|
|
return; \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
/* adjust src pointers for negative sizes */ \
|
|
if (xpos < 0) { \
|
|
src += -xpos * 8; \
|
|
src_width -= -xpos; \
|
|
xpos = 0; \
|
|
} \
|
|
if (ypos < dst_y_start) { \
|
|
src += (dst_y_start - ypos) * src_stride; \
|
|
src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
/* 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 > dst_y_end) { \
|
|
src_height = dst_y_end - ypos; \
|
|
} \
|
|
\
|
|
if (src_height > 0 && src_width > 0) { \
|
|
dest = dest + 8 * xpos + (ypos * dest_stride); \
|
|
\
|
|
LOOP (dest, src, src_height, src_width, src_stride, dest_stride, s_alpha, \
|
|
mode); \
|
|
} \
|
|
}
|
|
|
|
#define OVERLAY_A64_LOOP(name) \
|
|
static inline void \
|
|
_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 (G_MAXUINT16, s_alpha); \
|
|
switch (mode) { \
|
|
case COMPOSITOR_BLEND_MODE_SOURCE:\
|
|
if (s_alpha == G_MAXUINT16) { \
|
|
guint y; \
|
|
for (y = 0; y < src_height; y++) { \
|
|
memcpy (dest, src, 8 * src_width); \
|
|
dest += dest_stride; \
|
|
src += src_stride; \
|
|
} \
|
|
} else { \
|
|
compositor_source_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
} \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_OVER:\
|
|
compositor_overlay_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_ADD:\
|
|
compositor_overlay_##name##_addition (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
}\
|
|
}
|
|
|
|
#define BLEND_A64_LOOP(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 (G_MAXUINT16, s_alpha); \
|
|
switch (mode) { \
|
|
case COMPOSITOR_BLEND_MODE_SOURCE:\
|
|
if (s_alpha == G_MAXUINT16) { \
|
|
guint y; \
|
|
for (y = 0; y < src_height; y++) { \
|
|
memcpy (dest, src, 8 * src_width); \
|
|
dest += dest_stride; \
|
|
src += src_stride; \
|
|
} \
|
|
} else { \
|
|
compositor_source_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
} \
|
|
break;\
|
|
case COMPOSITOR_BLEND_MODE_OVER:\
|
|
case COMPOSITOR_BLEND_MODE_ADD:\
|
|
/* both modes are the same for opaque background */ \
|
|
compositor_blend_##name (dest, dest_stride, src, src_stride, \
|
|
s_alpha, src_width, src_height); \
|
|
break;\
|
|
}\
|
|
}
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
OVERLAY_A64_LOOP (argb64);
|
|
BLEND_A64_LOOP (argb64);
|
|
BLEND_A64 (argb64, blend, _blend_loop_argb64);
|
|
BLEND_A64 (argb64, overlay, _overlay_loop_argb64);
|
|
#else
|
|
OVERLAY_A64_LOOP (bgra64);
|
|
BLEND_A64_LOOP (bgra64);
|
|
BLEND_A64 (argb64, blend, _blend_loop_bgra64);
|
|
BLEND_A64 (argb64, overlay, _overlay_loop_bgra64);
|
|
#endif
|
|
|
|
#define A64_CHECKER_C(name, RGB, A, C1, C2, C3) \
|
|
static void \
|
|
fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
gint val; \
|
|
static const gint tab[] = { 20480, 40960, 20480, 40960 }; \
|
|
static const gint uv = 1 << 15; \
|
|
gint width, stride; \
|
|
guint8 *dest; \
|
|
\
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
\
|
|
if (!RGB) { \
|
|
for (i = y_start; i < y_end; i++) { \
|
|
guint16 *data = (guint16 *) (dest + i * stride); \
|
|
for (j = 0; j < width; j++) { \
|
|
data[A] = 0xffff; \
|
|
data[C1] = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
|
|
data[C2] = uv; \
|
|
data[C3] = uv; \
|
|
data += 4; \
|
|
} \
|
|
} \
|
|
} else { \
|
|
for (i = y_start; i < y_end; i++) { \
|
|
guint16 *data = (guint16 *) (dest + i * stride); \
|
|
for (j = 0; j < width; j++) { \
|
|
val = tab[((i & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
|
|
data[A] = 0xffff; \
|
|
data[C1] = val; \
|
|
data[C2] = val; \
|
|
data[C3] = val; \
|
|
data += 4; \
|
|
} \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
A64_CHECKER_C (argb64, TRUE, 0, 1, 2, 3);
|
|
A64_CHECKER_C (ayuv64, FALSE, 0, 1, 2, 3);
|
|
|
|
#define A64_COLOR(name, A, C1, C2, C3) \
|
|
static void \
|
|
fill_color_##name (GstVideoFrame * frame, guint y_start, guint y_end, gint c1, gint c2, gint c3) \
|
|
{ \
|
|
gint i, j; \
|
|
gint stride; \
|
|
guint8 *dest; \
|
|
guint width; \
|
|
guint height; \
|
|
\
|
|
height = y_end - y_start; \
|
|
if (height <= 0) \
|
|
return; \
|
|
\
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
width = GST_VIDEO_FRAME_WIDTH (frame); \
|
|
\
|
|
for (i = y_start; i < y_end; i++) { \
|
|
guint16 *data = (guint16 *) (dest + i * stride); \
|
|
for (j = 0; j < width; j++) { \
|
|
data[A] = 0xffff; \
|
|
data[C1] = c1; \
|
|
data[C2] = c2; \
|
|
data[C3] = c3; \
|
|
data += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
A64_COLOR (argb64, 0, 1, 2, 3);
|
|
|
|
/* 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, GstCompositorBlendMode mode) \
|
|
{ \
|
|
gint i; \
|
|
gint b_alpha; \
|
|
\
|
|
/* in source mode we just have to copy over things */ \
|
|
if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
|
|
src_alpha = 1.0; \
|
|
} \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (src_alpha == 0.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 0.0)"); \
|
|
return; \
|
|
} \
|
|
\
|
|
/* If it's completely opaque, we do a fast copy */ \
|
|
if (G_UNLIKELY (src_alpha == 1.0)) { \
|
|
GST_LOG ("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 * 255), 0, 255); \
|
|
\
|
|
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, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
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); \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
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 < dst_y_start) { \
|
|
yoffset += dst_y_start - ypos; \
|
|
b_src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
/* 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 + b_src_width > dest_width) { \
|
|
b_src_width = dest_width - xpos; \
|
|
} \
|
|
if (ypos + b_src_height > dst_y_end) { \
|
|
b_src_height = dst_y_end - 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, mode); \
|
|
\
|
|
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); \
|
|
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 : ypos >> info->h_sub[1]; \
|
|
comp_xoffset = (xoffset == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (info, 1, xoffset); \
|
|
comp_yoffset = (yoffset == 0) ? 0 : yoffset >> info->h_sub[1]; \
|
|
_blend_##format_name (b_src + comp_xoffset * 2 + comp_yoffset * src_comp_rowstride, \
|
|
b_dest + comp_xpos * 2 + comp_ypos * dest_comp_rowstride, \
|
|
src_comp_rowstride, \
|
|
dest_comp_rowstride, 2 * src_comp_width, src_comp_height, \
|
|
src_alpha, mode); \
|
|
}
|
|
|
|
#define NV_YUV_FILL_CHECKER(format_name, MEMSET) \
|
|
static void \
|
|
fill_checker_##format_name (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
static const int tab[] = { 80, 160, 80, 160 }; \
|
|
guint8 *p; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
p = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
for (i = 0; i < comp_height; i++) { \
|
|
for (j = 0; j < comp_width; j++) { \
|
|
*p++ = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; \
|
|
} \
|
|
p += rowstride - comp_width; \
|
|
} \
|
|
\
|
|
p = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
p += comp_yoffset * rowstride; \
|
|
\
|
|
for (i = 0; i < comp_height; i++) { \
|
|
MEMSET (p, 0x80, comp_width * 2); \
|
|
p += rowstride; \
|
|
} \
|
|
}
|
|
|
|
#define NV_YUV_FILL_COLOR(format_name,MEMSET) \
|
|
static void \
|
|
fill_color_##format_name (GstVideoFrame * frame, \
|
|
guint y_start, guint y_end, gint colY, gint colU, gint colV) \
|
|
{ \
|
|
guint8 *y, *u, *v; \
|
|
gint comp_width, comp_height; \
|
|
gint rowstride, comp_yoffset; \
|
|
gint i, j; \
|
|
const GstVideoFormatInfo *info; \
|
|
\
|
|
info = frame->info.finfo; \
|
|
y = GST_VIDEO_FRAME_COMP_DATA (frame, 0); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 0, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
comp_yoffset = (y_start == 0) ? 0 : GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info, 0, y_start); \
|
|
\
|
|
y += comp_yoffset * rowstride; \
|
|
for (i = 0; i < comp_height; i++) { \
|
|
MEMSET (y, colY, comp_width); \
|
|
y += rowstride; \
|
|
} \
|
|
\
|
|
u = GST_VIDEO_FRAME_COMP_DATA (frame, 1); \
|
|
v = GST_VIDEO_FRAME_COMP_DATA (frame, 2); \
|
|
comp_width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); \
|
|
comp_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info, 1, y_end - y_start); \
|
|
rowstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); \
|
|
comp_yoffset = (y_start == 0) ? 0 : y_start >> info->h_sub[1]; \
|
|
\
|
|
u += comp_yoffset * rowstride; \
|
|
v += comp_yoffset * rowstride; \
|
|
for (i = 0; i < comp_height; i++) { \
|
|
for (j = 0; j < comp_width; j++) { \
|
|
u[j*2] = colU; \
|
|
v[j*2] = colV; \
|
|
} \
|
|
u += rowstride; \
|
|
v += rowstride; \
|
|
} \
|
|
}
|
|
|
|
NV_YUV_BLEND (nv12, memcpy, compositor_orc_blend_u8);
|
|
NV_YUV_FILL_CHECKER (nv12, memset);
|
|
NV_YUV_FILL_COLOR (nv12, memset);
|
|
NV_YUV_BLEND (nv21, memcpy, compositor_orc_blend_u8);
|
|
NV_YUV_FILL_CHECKER (nv21, memset);
|
|
|
|
/* RGB, BGR, xRGB, xBGR, RGBx, BGRx */
|
|
|
|
#define RGB_BLEND(name, bpp, MEMCPY, BLENDLOOP) \
|
|
static void \
|
|
blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
|
|
gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
gint b_alpha; \
|
|
gint i; \
|
|
gint src_stride, dest_stride; \
|
|
gint dest_width, dest_height; \
|
|
guint8 *dest, *src; \
|
|
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); \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
|
|
\
|
|
dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
|
|
dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
|
|
\
|
|
src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
|
|
dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
|
|
\
|
|
b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
/* adjust src pointers for negative sizes */ \
|
|
if (xpos < 0) { \
|
|
src += -xpos * bpp; \
|
|
src_width -= -xpos; \
|
|
xpos = 0; \
|
|
} \
|
|
if (ypos < dst_y_start) { \
|
|
src += (dst_y_start - ypos) * src_stride; \
|
|
src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
/* 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 > dst_y_end) { \
|
|
src_height = dst_y_end - ypos; \
|
|
} \
|
|
\
|
|
dest = dest + bpp * xpos + (ypos * dest_stride); \
|
|
\
|
|
/* in source mode we just have to copy over things */ \
|
|
if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
|
|
src_alpha = 1.0; \
|
|
} \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (src_alpha == 0.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 0.0)"); \
|
|
return; \
|
|
} \
|
|
\
|
|
/* If it's completely opaque, we do a fast copy */ \
|
|
if (G_UNLIKELY (src_alpha == 1.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 1.0)"); \
|
|
for (i = 0; i < src_height; i++) { \
|
|
MEMCPY (dest, src, bpp * src_width); \
|
|
src += src_stride; \
|
|
dest += dest_stride; \
|
|
} \
|
|
return; \
|
|
} \
|
|
\
|
|
BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, src_width * bpp, src_height); \
|
|
}
|
|
|
|
#define RGB_FILL_CHECKER_C(name, bpp, r, g, b) \
|
|
static void \
|
|
fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
static const int tab[] = { 80, 160, 80, 160 }; \
|
|
gint stride, dest_add, width, height; \
|
|
guint8 *dest; \
|
|
\
|
|
width = GST_VIDEO_FRAME_WIDTH (frame); \
|
|
height = y_end - y_start; \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
dest_add = stride - width * bpp; \
|
|
\
|
|
dest += y_start * stride; \
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[r] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* red */ \
|
|
dest[g] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* green */ \
|
|
dest[b] = tab[(((i + y_start) & 0x8) >> 3) + ((j & 0x8) >> 3)]; /* blue */ \
|
|
dest += bpp; \
|
|
} \
|
|
dest += dest_add; \
|
|
} \
|
|
}
|
|
|
|
#define RGB_FILL_COLOR(name, bpp, MEMSET_RGB) \
|
|
static void \
|
|
fill_color_##name (GstVideoFrame * frame, \
|
|
guint y_start, guint y_end, gint colR, gint colG, gint colB) \
|
|
{ \
|
|
gint i; \
|
|
gint dest_stride; \
|
|
gint width, height; \
|
|
guint8 *dest; \
|
|
\
|
|
width = GST_VIDEO_FRAME_WIDTH (frame); \
|
|
height = y_end - y_start; \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
\
|
|
dest += y_start * dest_stride; \
|
|
for (i = 0; i < height; i++) { \
|
|
MEMSET_RGB (dest, colR, colG, colB, width); \
|
|
dest += dest_stride; \
|
|
} \
|
|
}
|
|
|
|
#define MEMSET_RGB_C(name, r, g, b) \
|
|
static inline void \
|
|
_memset_##name##_c (guint8* dest, gint red, gint green, gint blue, gint width) { \
|
|
gint j; \
|
|
\
|
|
for (j = 0; j < width; j++) { \
|
|
dest[r] = red; \
|
|
dest[g] = green; \
|
|
dest[b] = blue; \
|
|
dest += 3; \
|
|
} \
|
|
}
|
|
|
|
#define MEMSET_XRGB(name, r, g, b) \
|
|
static inline void \
|
|
_memset_##name (guint8* dest, gint red, gint green, gint blue, gint width) { \
|
|
guint32 val; \
|
|
\
|
|
val = GUINT32_FROM_BE ((red << r) | (green << g) | (blue << b)); \
|
|
compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
|
|
}
|
|
|
|
#define _orc_memcpy_u32(dest,src,len) compositor_orc_memcpy_u32((guint32 *) dest, (const guint32 *) src, len/4)
|
|
|
|
RGB_BLEND (rgb, 3, memcpy, compositor_orc_blend_u8);
|
|
RGB_FILL_CHECKER_C (rgb, 3, 0, 1, 2);
|
|
MEMSET_RGB_C (rgb, 0, 1, 2);
|
|
RGB_FILL_COLOR (rgb_c, 3, _memset_rgb_c);
|
|
|
|
MEMSET_RGB_C (bgr, 2, 1, 0);
|
|
RGB_FILL_COLOR (bgr_c, 3, _memset_bgr_c);
|
|
|
|
RGB_BLEND (xrgb, 4, _orc_memcpy_u32, compositor_orc_blend_u8);
|
|
RGB_FILL_CHECKER_C (xrgb, 4, 1, 2, 3);
|
|
MEMSET_XRGB (xrgb, 24, 16, 0);
|
|
RGB_FILL_COLOR (xrgb, 4, _memset_xrgb);
|
|
|
|
MEMSET_XRGB (xbgr, 0, 16, 24);
|
|
RGB_FILL_COLOR (xbgr, 4, _memset_xbgr);
|
|
|
|
RGB_FILL_CHECKER_C (rgbx, 4, 0, 1, 2);
|
|
MEMSET_XRGB (rgbx, 24, 16, 8);
|
|
RGB_FILL_COLOR (rgbx, 4, _memset_rgbx);
|
|
|
|
MEMSET_XRGB (bgrx, 8, 16, 24);
|
|
RGB_FILL_COLOR (bgrx, 4, _memset_bgrx);
|
|
|
|
/* YUY2, YVYU, UYVY */
|
|
|
|
#define PACKED_422_BLEND(name, MEMCPY, BLENDLOOP) \
|
|
static void \
|
|
blend_##name (GstVideoFrame * srcframe, gint xpos, gint ypos, \
|
|
gdouble src_alpha, GstVideoFrame * destframe, gint dst_y_start, \
|
|
gint dst_y_end, GstCompositorBlendMode mode) \
|
|
{ \
|
|
gint b_alpha; \
|
|
gint i; \
|
|
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); \
|
|
\
|
|
dest_width = GST_VIDEO_FRAME_WIDTH (destframe); \
|
|
dest_height = GST_VIDEO_FRAME_HEIGHT (destframe); \
|
|
\
|
|
src = GST_VIDEO_FRAME_PLANE_DATA (srcframe, 0); \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (destframe, 0); \
|
|
\
|
|
src_stride = GST_VIDEO_FRAME_COMP_STRIDE (srcframe, 0); \
|
|
dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (destframe, 0); \
|
|
\
|
|
b_alpha = CLAMP ((gint) (src_alpha * 255), 0, 255); \
|
|
\
|
|
xpos = GST_ROUND_UP_2 (xpos); \
|
|
\
|
|
if (dst_y_end > dest_height) { \
|
|
dst_y_end = dest_height; \
|
|
} \
|
|
/* adjust src pointers for negative sizes */ \
|
|
if (xpos < 0) { \
|
|
src += -xpos * 2; \
|
|
src_width -= -xpos; \
|
|
xpos = 0; \
|
|
} \
|
|
if (ypos < dst_y_start) { \
|
|
src += (dst_y_start - ypos) * src_stride; \
|
|
src_height -= dst_y_start - ypos; \
|
|
ypos = dst_y_start; \
|
|
} \
|
|
\
|
|
/* 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 > dst_y_end) { \
|
|
src_height = dst_y_end - ypos; \
|
|
} \
|
|
\
|
|
dest = dest + 2 * xpos + (ypos * dest_stride); \
|
|
\
|
|
/* in source mode we just have to copy over things */ \
|
|
if (mode == COMPOSITOR_BLEND_MODE_SOURCE) { \
|
|
src_alpha = 1.0; \
|
|
} \
|
|
\
|
|
/* If it's completely transparent... we just return */ \
|
|
if (G_UNLIKELY (src_alpha == 0.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 0.0)"); \
|
|
return; \
|
|
} \
|
|
\
|
|
/* If it's completely opaque, we do a fast copy */ \
|
|
if (G_UNLIKELY (src_alpha == 1.0)) { \
|
|
GST_LOG ("Fast copy (alpha == 1.0)"); \
|
|
for (i = 0; i < src_height; i++) { \
|
|
MEMCPY (dest, src, 2 * src_width); \
|
|
src += src_stride; \
|
|
dest += dest_stride; \
|
|
} \
|
|
return; \
|
|
} \
|
|
\
|
|
BLENDLOOP(dest, dest_stride, src, src_stride, b_alpha, 2 * src_width, src_height); \
|
|
}
|
|
|
|
#define PACKED_422_FILL_CHECKER_C(name, Y1, U, Y2, V) \
|
|
static void \
|
|
fill_checker_##name##_c (GstVideoFrame * frame, guint y_start, guint y_end) \
|
|
{ \
|
|
gint i, j; \
|
|
static const int tab[] = { 80, 160, 80, 160 }; \
|
|
gint dest_add; \
|
|
gint width, height; \
|
|
guint8 *dest; \
|
|
\
|
|
width = GST_VIDEO_FRAME_WIDTH (frame); \
|
|
width = GST_ROUND_UP_2 (width); \
|
|
height = y_end - y_start; \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
dest_add = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) - width * 2; \
|
|
width /= 2; \
|
|
\
|
|
dest += GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * y_start; \
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[Y1] = tab[(((i + y_start) & 0x8) >> 3) + (((2 * j + 0) & 0x8) >> 3)]; \
|
|
dest[Y2] = tab[(((i + y_start) & 0x8) >> 3) + (((2 * j + 1) & 0x8) >> 3)]; \
|
|
dest[U] = 128; \
|
|
dest[V] = 128; \
|
|
dest += 4; \
|
|
} \
|
|
dest += dest_add; \
|
|
} \
|
|
}
|
|
|
|
#define PACKED_422_FILL_COLOR(name, Y1, U, Y2, V) \
|
|
static void \
|
|
fill_color_##name (GstVideoFrame * frame, \
|
|
guint y_start, guint y_end, gint colY, gint colU, gint colV) \
|
|
{ \
|
|
gint i; \
|
|
gint dest_stride; \
|
|
guint32 val; \
|
|
gint width, height; \
|
|
guint8 *dest; \
|
|
\
|
|
width = GST_VIDEO_FRAME_WIDTH (frame); \
|
|
width = GST_ROUND_UP_2 (width); \
|
|
height = y_end - y_start; \
|
|
dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); \
|
|
dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); \
|
|
width /= 2; \
|
|
\
|
|
val = GUINT32_FROM_BE ((colY << Y1) | (colY << Y2) | (colU << U) | (colV << V)); \
|
|
\
|
|
dest += dest_stride * y_start; \
|
|
for (i = 0; i < height; i++) { \
|
|
compositor_orc_splat_u32 ((guint32 *) dest, val, width); \
|
|
dest += dest_stride; \
|
|
} \
|
|
}
|
|
|
|
PACKED_422_BLEND (yuy2, memcpy, compositor_orc_blend_u8);
|
|
PACKED_422_FILL_CHECKER_C (yuy2, 0, 1, 2, 3);
|
|
PACKED_422_FILL_CHECKER_C (uyvy, 1, 0, 3, 2);
|
|
PACKED_422_FILL_COLOR (yuy2, 24, 16, 8, 0);
|
|
PACKED_422_FILL_COLOR (yvyu, 24, 0, 8, 16);
|
|
PACKED_422_FILL_COLOR (uyvy, 16, 24, 0, 8);
|
|
|
|
/* Init function */
|
|
BlendFunction gst_compositor_blend_argb;
|
|
BlendFunction gst_compositor_blend_bgra;
|
|
BlendFunction gst_compositor_overlay_argb;
|
|
BlendFunction gst_compositor_overlay_bgra;
|
|
/* AYUV/ABGR is equal to ARGB, RGBA is equal to BGRA */
|
|
BlendFunction gst_compositor_blend_y444;
|
|
BlendFunction gst_compositor_blend_y42b;
|
|
BlendFunction gst_compositor_blend_i420;
|
|
/* I420 is equal to YV12 */
|
|
BlendFunction gst_compositor_blend_nv12;
|
|
BlendFunction gst_compositor_blend_nv21;
|
|
BlendFunction gst_compositor_blend_y41b;
|
|
BlendFunction gst_compositor_blend_rgb;
|
|
/* BGR is equal to RGB */
|
|
BlendFunction gst_compositor_blend_rgbx;
|
|
/* BGRx, xRGB, xBGR are equal to RGBx */
|
|
BlendFunction gst_compositor_blend_yuy2;
|
|
/* YVYU and UYVY are equal to YUY2 */
|
|
BlendFunction gst_compositor_blend_i420_10le;
|
|
BlendFunction gst_compositor_blend_i420_10be;
|
|
BlendFunction gst_compositor_blend_i420_12le;
|
|
BlendFunction gst_compositor_blend_i420_12be;
|
|
BlendFunction gst_compositor_blend_i422_10le;
|
|
BlendFunction gst_compositor_blend_i422_10be;
|
|
BlendFunction gst_compositor_blend_i422_12le;
|
|
BlendFunction gst_compositor_blend_i422_12be;
|
|
BlendFunction gst_compositor_blend_y444_10le;
|
|
BlendFunction gst_compositor_blend_y444_10be;
|
|
BlendFunction gst_compositor_blend_y444_12le;
|
|
BlendFunction gst_compositor_blend_y444_12be;
|
|
BlendFunction gst_compositor_blend_y444_16le;
|
|
BlendFunction gst_compositor_blend_y444_16be;
|
|
BlendFunction gst_compositor_blend_argb64;
|
|
BlendFunction gst_compositor_overlay_argb64;
|
|
/* AYUV64 is equal to ARGB64 */
|
|
|
|
FillCheckerFunction gst_compositor_fill_checker_argb;
|
|
FillCheckerFunction gst_compositor_fill_checker_bgra;
|
|
/* ABGR is equal to ARGB, RGBA is equal to BGRA */
|
|
FillCheckerFunction gst_compositor_fill_checker_ayuv;
|
|
FillCheckerFunction gst_compositor_fill_checker_vuya;
|
|
FillCheckerFunction gst_compositor_fill_checker_y444;
|
|
FillCheckerFunction gst_compositor_fill_checker_y42b;
|
|
FillCheckerFunction gst_compositor_fill_checker_i420;
|
|
/* I420 is equal to YV12 */
|
|
FillCheckerFunction gst_compositor_fill_checker_nv12;
|
|
FillCheckerFunction gst_compositor_fill_checker_nv21;
|
|
FillCheckerFunction gst_compositor_fill_checker_y41b;
|
|
FillCheckerFunction gst_compositor_fill_checker_rgb;
|
|
/* BGR is equal to RGB */
|
|
FillCheckerFunction gst_compositor_fill_checker_xrgb;
|
|
FillCheckerFunction gst_compositor_fill_checker_rgbx;
|
|
/* BGRx, xRGB, xBGR are equal to RGBx */
|
|
FillCheckerFunction gst_compositor_fill_checker_yuy2;
|
|
/* YVYU is equal to YUY2 */
|
|
FillCheckerFunction gst_compositor_fill_checker_uyvy;
|
|
FillCheckerFunction gst_compositor_fill_checker_i420_10le;
|
|
FillCheckerFunction gst_compositor_fill_checker_i420_10be;
|
|
FillCheckerFunction gst_compositor_fill_checker_i420_12le;
|
|
FillCheckerFunction gst_compositor_fill_checker_i420_12be;
|
|
FillCheckerFunction gst_compositor_fill_checker_y444_16le;
|
|
FillCheckerFunction gst_compositor_fill_checker_y444_16be;
|
|
FillCheckerFunction gst_compositor_fill_checker_argb64;
|
|
FillCheckerFunction gst_compositor_fill_checker_ayuv64;
|
|
|
|
FillColorFunction gst_compositor_fill_color_argb;
|
|
FillColorFunction gst_compositor_fill_color_bgra;
|
|
FillColorFunction gst_compositor_fill_color_abgr;
|
|
FillColorFunction gst_compositor_fill_color_rgba;
|
|
FillColorFunction gst_compositor_fill_color_ayuv;
|
|
FillColorFunction gst_compositor_fill_color_vuya;
|
|
FillColorFunction gst_compositor_fill_color_y444;
|
|
FillColorFunction gst_compositor_fill_color_y42b;
|
|
FillColorFunction gst_compositor_fill_color_i420;
|
|
FillColorFunction gst_compositor_fill_color_yv12;
|
|
FillColorFunction gst_compositor_fill_color_nv12;
|
|
/* NV21 is equal to NV12 */
|
|
FillColorFunction gst_compositor_fill_color_y41b;
|
|
FillColorFunction gst_compositor_fill_color_rgb;
|
|
FillColorFunction gst_compositor_fill_color_bgr;
|
|
FillColorFunction gst_compositor_fill_color_xrgb;
|
|
FillColorFunction gst_compositor_fill_color_xbgr;
|
|
FillColorFunction gst_compositor_fill_color_rgbx;
|
|
FillColorFunction gst_compositor_fill_color_bgrx;
|
|
FillColorFunction gst_compositor_fill_color_yuy2;
|
|
FillColorFunction gst_compositor_fill_color_yvyu;
|
|
FillColorFunction gst_compositor_fill_color_uyvy;
|
|
FillColorFunction gst_compositor_fill_color_i420_10le;
|
|
FillColorFunction gst_compositor_fill_color_i420_10be;
|
|
FillColorFunction gst_compositor_fill_color_i420_12le;
|
|
FillColorFunction gst_compositor_fill_color_i420_12be;
|
|
FillColorFunction gst_compositor_fill_color_y444_16le;
|
|
FillColorFunction gst_compositor_fill_color_y444_16be;
|
|
FillColorFunction gst_compositor_fill_color_argb64;
|
|
|
|
void
|
|
gst_compositor_init_blend (void)
|
|
{
|
|
GST_DEBUG_CATEGORY_INIT (gst_compositor_blend_debug, "compositor_blend", 0,
|
|
"video compositor blending functions");
|
|
|
|
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_blend_i420_10le = GST_DEBUG_FUNCPTR (blend_i420_10le);
|
|
gst_compositor_blend_i420_10be = GST_DEBUG_FUNCPTR (blend_i420_10be);
|
|
gst_compositor_blend_i420_12le = GST_DEBUG_FUNCPTR (blend_i420_12le);
|
|
gst_compositor_blend_i420_12be = GST_DEBUG_FUNCPTR (blend_i420_12be);
|
|
gst_compositor_blend_i422_10le = GST_DEBUG_FUNCPTR (blend_i422_10le);
|
|
gst_compositor_blend_i422_10be = GST_DEBUG_FUNCPTR (blend_i422_10be);
|
|
gst_compositor_blend_i422_12le = GST_DEBUG_FUNCPTR (blend_i422_12le);
|
|
gst_compositor_blend_i422_12be = GST_DEBUG_FUNCPTR (blend_i422_12be);
|
|
gst_compositor_blend_y444_10le = GST_DEBUG_FUNCPTR (blend_y444_10le);
|
|
gst_compositor_blend_y444_10be = GST_DEBUG_FUNCPTR (blend_y444_10be);
|
|
gst_compositor_blend_y444_12le = GST_DEBUG_FUNCPTR (blend_y444_12le);
|
|
gst_compositor_blend_y444_12be = GST_DEBUG_FUNCPTR (blend_y444_12be);
|
|
gst_compositor_blend_y444_16le = GST_DEBUG_FUNCPTR (blend_y444_16le);
|
|
gst_compositor_blend_y444_16be = GST_DEBUG_FUNCPTR (blend_y444_16be);
|
|
gst_compositor_blend_argb64 = GST_DEBUG_FUNCPTR (blend_argb64);
|
|
gst_compositor_overlay_argb64 = GST_DEBUG_FUNCPTR (overlay_argb64);
|
|
|
|
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_vuya = GST_DEBUG_FUNCPTR (fill_checker_vuya_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_rgbx = GST_DEBUG_FUNCPTR (fill_checker_rgbx_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_checker_i420_10le =
|
|
GST_DEBUG_FUNCPTR (fill_checker_i420_10le);
|
|
gst_compositor_fill_checker_i420_10be =
|
|
GST_DEBUG_FUNCPTR (fill_checker_i420_10be);
|
|
gst_compositor_fill_checker_i420_12le =
|
|
GST_DEBUG_FUNCPTR (fill_checker_i420_12le);
|
|
gst_compositor_fill_checker_i420_12be =
|
|
GST_DEBUG_FUNCPTR (fill_checker_i420_12be);
|
|
gst_compositor_fill_checker_y444_16le =
|
|
GST_DEBUG_FUNCPTR (fill_checker_y444_16le);
|
|
gst_compositor_fill_checker_y444_16be =
|
|
GST_DEBUG_FUNCPTR (fill_checker_y444_16be);
|
|
gst_compositor_fill_checker_argb64 =
|
|
GST_DEBUG_FUNCPTR (fill_checker_argb64_c);
|
|
gst_compositor_fill_checker_ayuv64 =
|
|
GST_DEBUG_FUNCPTR (fill_checker_ayuv64_c);
|
|
|
|
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_vuya = GST_DEBUG_FUNCPTR (fill_color_vuya);
|
|
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);
|
|
gst_compositor_fill_color_i420_10le =
|
|
GST_DEBUG_FUNCPTR (fill_color_i420_10le);
|
|
gst_compositor_fill_color_i420_10be =
|
|
GST_DEBUG_FUNCPTR (fill_color_i420_10be);
|
|
gst_compositor_fill_color_i420_12le =
|
|
GST_DEBUG_FUNCPTR (fill_color_i420_12le);
|
|
gst_compositor_fill_color_i420_12be =
|
|
GST_DEBUG_FUNCPTR (fill_color_i420_12be);
|
|
gst_compositor_fill_color_y444_16le =
|
|
GST_DEBUG_FUNCPTR (fill_color_y444_16le);
|
|
gst_compositor_fill_color_y444_16be =
|
|
GST_DEBUG_FUNCPTR (fill_color_y444_16be);
|
|
gst_compositor_fill_color_argb64 = GST_DEBUG_FUNCPTR (fill_color_argb64);
|
|
}
|