video: blend using OVER operation
Also support all premultiplied/non-premultiplied source/destination configurations https://bugzilla.gnome.org/show_bug.cgi?id=681447
This commit is contained in:
parent
cab8671f0c
commit
dfe250d17d
@ -136,16 +136,6 @@ matrix_yuv_to_rgb (guint8 * tmpline, guint width)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLEND00(ret, alpha, v0, v1) \
|
|
||||||
G_STMT_START { \
|
|
||||||
ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
#define BLEND10(ret, alpha, v0, v1) \
|
|
||||||
G_STMT_START { \
|
|
||||||
ret = v0 + (v1 * (255 - alpha)) / 255; \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_video_blend_scale_linear_RGBA:
|
* gst_video_blend_scale_linear_RGBA:
|
||||||
* @src: the #GstVideoInfo describing the video data in @src_buffer
|
* @src: the #GstVideoInfo describing the video data in @src_buffer
|
||||||
@ -248,6 +238,41 @@ gst_video_blend_scale_linear_RGBA (GstVideoInfo * src, GstBuffer * src_buffer,
|
|||||||
g_free (tmpbuf);
|
g_free (tmpbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A OVER B alpha compositing operation, with:
|
||||||
|
* alphaG: global alpha to apply on the source color
|
||||||
|
* -> only needed for premultiplied source
|
||||||
|
* alphaA: source pixel alpha
|
||||||
|
* colorA: source pixel color
|
||||||
|
* alphaB: destination pixel alpha
|
||||||
|
* colorB: destination pixel color
|
||||||
|
* alphaD: blended pixel alpha
|
||||||
|
* -> only needed for premultiplied destination
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Source non-premultiplied, Destination non-premultiplied */
|
||||||
|
#define OVER00(alphaG, alphaA, colorA, alphaB, colorB, alphaD) \
|
||||||
|
((colorA * alphaA + colorB * alphaB * (255 - alphaA) / 255) / alphaD)
|
||||||
|
|
||||||
|
/* Source premultiplied, Destination non-premultiplied */
|
||||||
|
#define OVER10(alphaG, alphaA, colorA, alphaB, colorB, alphaD) \
|
||||||
|
((colorA * alphaG + colorB * alphaB * (255 - alphaA) / 255) / alphaD)
|
||||||
|
|
||||||
|
/* Source non-premultiplied, Destination premultiplied */
|
||||||
|
#define OVER01(alphaG, alphaA, colorA, alphaB, colorB, alphaD) \
|
||||||
|
((colorA * alphaA + colorB * (255 - alphaA)) / 255)
|
||||||
|
|
||||||
|
/* Source premultiplied, Destination premultiplied */
|
||||||
|
#define OVER11(alphaG, alphaA, colorA, alphaB, colorB, alphaD) \
|
||||||
|
((colorA * alphaG + colorB * (255 - alphaA)) / 255)
|
||||||
|
|
||||||
|
#define BLENDC(op, global_alpha, aa, ca, ab, cb, dest_alpha) \
|
||||||
|
G_STMT_START { \
|
||||||
|
int c = op(global_alpha, aa, ca, ab, cb, dest_alpha); \
|
||||||
|
cb = MIN(c, 255); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_video_blend:
|
* gst_video_blend:
|
||||||
* @dest: The #GstVideoFrame where to blend @src in
|
* @dest: The #GstVideoFrame where to blend @src in
|
||||||
@ -273,17 +298,13 @@ gst_video_blend (GstVideoFrame * dest,
|
|||||||
g_assert (dest != NULL);
|
g_assert (dest != NULL);
|
||||||
g_assert (src != NULL);
|
g_assert (src != NULL);
|
||||||
|
|
||||||
global_alpha_val = 256.0 * global_alpha;
|
global_alpha_val = 255.0 * global_alpha;
|
||||||
|
|
||||||
dest_premultiplied_alpha =
|
dest_premultiplied_alpha =
|
||||||
GST_VIDEO_INFO_FLAGS (&dest->info) & GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
GST_VIDEO_INFO_FLAGS (&dest->info) & GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||||
src_premultiplied_alpha =
|
src_premultiplied_alpha =
|
||||||
GST_VIDEO_INFO_FLAGS (&src->info) & GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
GST_VIDEO_INFO_FLAGS (&src->info) & GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||||
|
|
||||||
/* we do no support writing to premultiplied alpha, though that should
|
|
||||||
just be a matter of adding blenders below (BLEND01 and BLEND11) */
|
|
||||||
g_return_val_if_fail (!dest_premultiplied_alpha, FALSE);
|
|
||||||
|
|
||||||
src_width = GST_VIDEO_FRAME_WIDTH (src);
|
src_width = GST_VIDEO_FRAME_WIDTH (src);
|
||||||
src_height = GST_VIDEO_FRAME_HEIGHT (src);
|
src_height = GST_VIDEO_FRAME_HEIGHT (src);
|
||||||
|
|
||||||
@ -372,40 +393,47 @@ gst_video_blend (GstVideoFrame * dest,
|
|||||||
|
|
||||||
matrix (tmpsrcline, src_width);
|
matrix (tmpsrcline, src_width);
|
||||||
|
|
||||||
/* Here dest and src are both either in AYUV or ARGB
|
#define BLENDLOOP(op, alpha_val) \
|
||||||
* TODO: Make the orc version working properly*/
|
G_STMT_START { \
|
||||||
#define BLENDLOOP(blender,alpha_val,alpha_scale) \
|
for (j = 0; j < src_width * 4; j += 4) { \
|
||||||
do { \
|
guint8 asrc, adst; \
|
||||||
for (j = 0; j < src_width * 4; j += 4) { \
|
gint final_alpha; \
|
||||||
guint8 alpha; \
|
\
|
||||||
\
|
asrc = tmpsrcline[j] * alpha_val / 255; \
|
||||||
alpha = (tmpsrcline[j] * alpha_val) / alpha_scale; \
|
if (!asrc) \
|
||||||
\
|
continue; \
|
||||||
blender (tmpdestline[j + 1], alpha, tmpsrcline[j + 1], tmpdestline[j + 1]); \
|
\
|
||||||
blender (tmpdestline[j + 2], alpha, tmpsrcline[j + 2], tmpdestline[j + 2]); \
|
adst = tmpdestline[j]; \
|
||||||
blender (tmpdestline[j + 3], alpha, tmpsrcline[j + 3], tmpdestline[j + 3]); \
|
final_alpha = asrc + adst * (255 - asrc) / 255; \
|
||||||
} \
|
tmpdestline[j] = final_alpha; \
|
||||||
} while(0)
|
if (final_alpha == 0) \
|
||||||
|
final_alpha = 1; \
|
||||||
|
\
|
||||||
|
BLENDC (op, alpha_val, asrc, tmpsrcline[j + 1], adst, tmpdestline[j + 1], final_alpha); \
|
||||||
|
BLENDC (op, alpha_val, asrc, tmpsrcline[j + 2], adst, tmpdestline[j + 2], final_alpha); \
|
||||||
|
BLENDC (op, alpha_val, asrc, tmpsrcline[j + 3], adst, tmpdestline[j + 3], final_alpha); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
if (G_LIKELY (global_alpha == 1.0)) {
|
if (G_LIKELY (global_alpha == 1.0)) {
|
||||||
if (src_premultiplied_alpha && dest_premultiplied_alpha) {
|
if (src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||||
/* BLENDLOOP (BLEND11, 1, 1); */
|
BLENDLOOP (OVER11, 255);
|
||||||
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||||
/* BLENDLOOP (BLEND01, 1, 1); */
|
BLENDLOOP (OVER01, 255);
|
||||||
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
||||||
BLENDLOOP (BLEND10, 1, 1);
|
BLENDLOOP (OVER10, 255);
|
||||||
} else {
|
} else {
|
||||||
BLENDLOOP (BLEND00, 1, 1);
|
BLENDLOOP (OVER00, 255);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (src_premultiplied_alpha && dest_premultiplied_alpha) {
|
if (src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||||
/* BLENDLOOP (BLEND11, global_alpha_val, 256); */
|
BLENDLOOP (OVER11, global_alpha_val);
|
||||||
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||||
/* BLENDLOOP (BLEND01, global_alpha_val, 256); */
|
BLENDLOOP (OVER01, global_alpha_val);
|
||||||
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
||||||
BLENDLOOP (BLEND10, global_alpha_val, 256);
|
BLENDLOOP (OVER10, global_alpha_val);
|
||||||
} else {
|
} else {
|
||||||
BLENDLOOP (BLEND00, global_alpha_val, 256);
|
BLENDLOOP (OVER00, global_alpha_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user