mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-23 15:48:23 +00:00
videooverlaycomposition: port to 0.11
... which also entails porting video-blend Fixes #678384.
This commit is contained in:
parent
3a1b53c117
commit
e94022806f
5 changed files with 317 additions and 249 deletions
|
@ -35,7 +35,9 @@ libgstvideo_@GST_API_VERSION@_la_SOURCES = \
|
|||
videooverlay.c \
|
||||
gstvideodecoder.c \
|
||||
gstvideoencoder.c \
|
||||
gstvideoutils.c
|
||||
gstvideoutils.c \
|
||||
video-blend.c \
|
||||
video-overlay-composition.c
|
||||
|
||||
nodist_libgstvideo_@GST_API_VERSION@_la_SOURCES = $(BUILT_SOURCES)
|
||||
|
||||
|
@ -58,7 +60,10 @@ libgstvideo_@GST_API_VERSION@include_HEADERS = \
|
|||
videooverlay.h \
|
||||
gstvideodecoder.h \
|
||||
gstvideoencoder.h \
|
||||
gstvideoutils.h
|
||||
gstvideoutils.h \
|
||||
video-blend.h \
|
||||
video-overlay-composition.h
|
||||
|
||||
nodist_libgstvideo_@GST_API_VERSION@include_HEADERS = $(built_headers)
|
||||
|
||||
libgstvideo_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) \
|
||||
|
|
|
@ -146,10 +146,11 @@ G_STMT_START { \
|
|||
ret = v0 + (v1 * (255 - alpha)) / 255; \
|
||||
} G_STMT_END
|
||||
|
||||
/* returns newly-allocated pixels in src->pixels, which caller must g_free() */
|
||||
/* returns newly-allocated buffer, which caller must unref */
|
||||
void
|
||||
gst_video_blend_scale_linear_RGBA (GstVideoFrame * src,
|
||||
gint dest_height, gint dest_width)
|
||||
gst_video_blend_scale_linear_RGBA (GstVideoInfo * src, GstBuffer * src_buffer,
|
||||
gint dest_height, gint dest_width, GstVideoInfo * dest,
|
||||
GstBuffer ** dest_buffer)
|
||||
{
|
||||
const guint8 *src_pixels;
|
||||
int acc;
|
||||
|
@ -162,11 +163,20 @@ gst_video_blend_scale_linear_RGBA (GstVideoFrame * src,
|
|||
int dest_size;
|
||||
guint dest_stride = dest_width * 4;
|
||||
guint src_stride = src->width * 4;
|
||||
|
||||
guint8 *dest_pixels;
|
||||
guint8 *tmpbuf = g_malloc (dest_width * 8 * 4);
|
||||
guint8 *dest_pixels =
|
||||
g_malloc (gst_video_format_get_size (src->fmt, dest_height,
|
||||
dest_width));
|
||||
GstVideoFrame src_frame, dest_frame;
|
||||
|
||||
g_return_if_fail (dest_buffer != NULL);
|
||||
|
||||
gst_video_info_init (dest);
|
||||
gst_video_info_set_format (dest, GST_VIDEO_INFO_FORMAT (src),
|
||||
dest_width, dest_height);
|
||||
|
||||
*dest_buffer = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (dest));
|
||||
|
||||
gst_video_frame_map (&src_frame, src, src_buffer, GST_MAP_READ);
|
||||
gst_video_frame_map (&dest_frame, dest, *dest_buffer, GST_MAP_WRITE);
|
||||
|
||||
if (dest_height == 1)
|
||||
y_increment = 0;
|
||||
|
@ -182,7 +192,8 @@ gst_video_blend_scale_linear_RGBA (GstVideoFrame * src,
|
|||
|
||||
#define LINE(x) ((tmpbuf) + (dest_size)*((x)&1))
|
||||
|
||||
src_pixels = src->pixels;
|
||||
dest_pixels = GST_VIDEO_FRAME_PLANE_DATA (&dest_frame, 0);
|
||||
src_pixels = GST_VIDEO_FRAME_PLANE_DATA (&src_frame, 0);
|
||||
|
||||
acc = 0;
|
||||
orc_resample_bilinear_u32 (LINE (0), src_pixels, 0, x_increment, dest_width);
|
||||
|
@ -211,9 +222,8 @@ gst_video_blend_scale_linear_RGBA (GstVideoFrame * src,
|
|||
acc += y_increment;
|
||||
}
|
||||
|
||||
/* Update src, our reference to the old src->pixels is lost */
|
||||
video_blend_format_info_init (src, dest_pixels, dest_height, dest_width,
|
||||
src->fmt, src->premultiplied_alpha);
|
||||
gst_video_frame_unmap (&src_frame);
|
||||
gst_video_frame_unmap (&dest_frame);
|
||||
|
||||
g_free (tmpbuf);
|
||||
}
|
||||
|
@ -233,78 +243,90 @@ gboolean
|
|||
gst_video_blend (GstVideoFrame * dest,
|
||||
GstVideoFrame * src, guint x, guint y, gfloat global_alpha)
|
||||
{
|
||||
guint i, j, global_alpha_val, src_width, src_height;
|
||||
GetPutLine getputdest, getputsrc;
|
||||
gint src_stride;
|
||||
guint i, j, global_alpha_val, src_width, src_height, dest_width, dest_height;
|
||||
gint xoff;
|
||||
guint8 *tmpdestline = NULL, *tmpsrcline = NULL;
|
||||
gboolean src_premultiplied_alpha;
|
||||
gboolean src_premultiplied_alpha, dest_premultiplied_alpha;
|
||||
void (*matrix) (guint8 * tmpline, guint width);
|
||||
const GstVideoFormatInfo *sinfo, *dinfo;
|
||||
|
||||
g_assert (dest != NULL);
|
||||
g_assert (src != NULL);
|
||||
|
||||
global_alpha_val = 256.0 * global_alpha;
|
||||
|
||||
dest_premultiplied_alpha =
|
||||
GST_VIDEO_INFO_FLAGS (&dest->info) & GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||
src_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_premultiplied_alpha = src->premultiplied_alpha;
|
||||
g_return_val_if_fail (!dest_premultiplied_alpha, FALSE);
|
||||
|
||||
src_stride = src->width * 4;
|
||||
tmpdestline = g_malloc (sizeof (guint8) * (dest->width + 8) * 4);
|
||||
tmpsrcline = g_malloc (sizeof (guint8) * (dest->width + 8) * 4);
|
||||
src_width = GST_VIDEO_FRAME_WIDTH (src);
|
||||
src_height = GST_VIDEO_FRAME_HEIGHT (src);
|
||||
|
||||
dest_width = GST_VIDEO_FRAME_WIDTH (dest);
|
||||
dest_height = GST_VIDEO_FRAME_HEIGHT (dest);
|
||||
|
||||
tmpdestline = g_malloc (sizeof (guint8) * (dest_width + 8) * 4);
|
||||
tmpsrcline = g_malloc (sizeof (guint8) * (dest_width + 8) * 4);
|
||||
|
||||
ensure_debug_category ();
|
||||
|
||||
dinfo = gst_video_format_get_info (GST_VIDEO_FRAME_FORMAT (dest));
|
||||
sinfo = gst_video_format_get_info (GST_VIDEO_FRAME_FORMAT (src));
|
||||
|
||||
if (!lookup_getput (&getputdest, dest->fmt))
|
||||
if (!sinfo || !dinfo)
|
||||
goto failed;
|
||||
|
||||
if (!lookup_getput (&getputsrc, src->fmt))
|
||||
goto failed;
|
||||
|
||||
if (gst_video_format_is_rgb (src->fmt) != gst_video_format_is_rgb (dest->fmt)) {
|
||||
if (gst_video_format_is_rgb (src->fmt)) {
|
||||
matrix = matrix_identity;
|
||||
if (GST_VIDEO_INFO_IS_RGB (&src->info) != GST_VIDEO_INFO_IS_RGB (&dest->info)) {
|
||||
if (GST_VIDEO_INFO_IS_RGB (&src->info)) {
|
||||
if (src_premultiplied_alpha) {
|
||||
getputsrc.matrix = matrix_prea_rgb_to_yuv;
|
||||
matrix = matrix_prea_rgb_to_yuv;
|
||||
src_premultiplied_alpha = FALSE;
|
||||
} else {
|
||||
getputsrc.matrix = matrix_rgb_to_yuv;
|
||||
matrix = matrix_rgb_to_yuv;
|
||||
}
|
||||
} else {
|
||||
getputsrc.matrix = matrix_yuv_to_rgb;
|
||||
matrix = matrix_yuv_to_rgb;
|
||||
}
|
||||
}
|
||||
|
||||
xoff = 0;
|
||||
|
||||
/* adjust src pointers for negative sizes */
|
||||
if (x < 0) {
|
||||
src += -x * 4;
|
||||
src->width -= -x;
|
||||
src_width -= -x;
|
||||
x = 0;
|
||||
xoff = -x;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
src += -y * src_stride;
|
||||
src->height -= -y;
|
||||
src_height -= -y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
/* adjust width/height if the src is bigger than dest */
|
||||
if (x + src->width > dest->width)
|
||||
src->width = dest->width - x;
|
||||
if (x + src_width > dest_width)
|
||||
src_width = dest_width - x;
|
||||
|
||||
if (y + src->height > dest->height)
|
||||
src->height = dest->height - y;
|
||||
|
||||
src_width = src->width;
|
||||
src_height = src->height;
|
||||
if (y + src_height > dest_height)
|
||||
src_height = dest_height - y;
|
||||
|
||||
/* Mainloop doing the needed conversions, and blending */
|
||||
for (i = y; i < y + src_height; i++) {
|
||||
|
||||
getputdest.getline (tmpdestline, dest, x, i);
|
||||
getputsrc.getline (tmpsrcline, src, 0, (i - y));
|
||||
dinfo->unpack_func (dinfo, 0, tmpdestline, dest->data, dest->info.stride,
|
||||
0, i, dest_width);
|
||||
sinfo->unpack_func (sinfo, 0, tmpsrcline, src->data, src->info.stride,
|
||||
xoff, i - y, src_width - xoff);
|
||||
|
||||
getputsrc.matrix (tmpsrcline, src_width);
|
||||
matrix (tmpsrcline, src_width);
|
||||
|
||||
tmpdestline += 4 * x;
|
||||
|
||||
/* Here dest and src are both either in AYUV or ARGB
|
||||
* TODO: Make the orc version working properly*/
|
||||
|
@ -322,21 +344,21 @@ gst_video_blend (GstVideoFrame * dest,
|
|||
} while(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); */
|
||||
} else if (!src_premultiplied_alpha && dest->premultiplied_alpha) {
|
||||
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||
/* BLENDLOOP (BLEND01, 1, 1); */
|
||||
} else if (src_premultiplied_alpha && !dest->premultiplied_alpha) {
|
||||
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
||||
BLENDLOOP (BLEND10, 1, 1);
|
||||
} else {
|
||||
BLENDLOOP (BLEND00, 1, 1);
|
||||
}
|
||||
} else {
|
||||
if (src_premultiplied_alpha && dest->premultiplied_alpha) {
|
||||
if (src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||
/* BLENDLOOP (BLEND11, global_alpha_val, 256); */
|
||||
} else if (!src_premultiplied_alpha && dest->premultiplied_alpha) {
|
||||
} else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
|
||||
/* BLENDLOOP (BLEND01, global_alpha_val, 256); */
|
||||
} else if (src_premultiplied_alpha && !dest->premultiplied_alpha) {
|
||||
} else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
|
||||
BLENDLOOP (BLEND10, global_alpha_val, 256);
|
||||
} else {
|
||||
BLENDLOOP (BLEND00, global_alpha_val, 256);
|
||||
|
@ -345,6 +367,8 @@ gst_video_blend (GstVideoFrame * dest,
|
|||
|
||||
#undef BLENDLOOP
|
||||
|
||||
tmpdestline -= 4 * x;
|
||||
|
||||
/* FIXME
|
||||
* #if G_BYTE_ORDER == LITTLE_ENDIAN
|
||||
* orc_blend_little (tmpdestline, tmpsrcline, dest->width);
|
||||
|
@ -353,8 +377,8 @@ gst_video_blend (GstVideoFrame * dest,
|
|||
* #endif
|
||||
*/
|
||||
|
||||
getputdest.putline (dest, src, tmpdestline, x, i);
|
||||
|
||||
dinfo->pack_func (dinfo, 0, tmpdestline, dest_width,
|
||||
dest->data, dest->info.stride, dest->info.chroma_site, i, dest_width);
|
||||
}
|
||||
|
||||
g_free (tmpdestline);
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
void gst_video_blend_scale_linear_RGBA (GstVideoFrame * src,
|
||||
gint dest_height, gint dest_width);
|
||||
void gst_video_blend_scale_linear_RGBA (GstVideoInfo * src, GstBuffer * src_buffer,
|
||||
gint dest_height, gint dest_width,
|
||||
GstVideoInfo * dest, GstBuffer ** dest_buffer);
|
||||
|
||||
gboolean gst_video_blend (GstVideoFrame * dest,
|
||||
GstVideoFrame * src,
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
* </para>
|
||||
* </refsect2>
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
|
@ -88,11 +88,6 @@ struct _GstVideoOverlayComposition
|
|||
guint seq_num;
|
||||
};
|
||||
|
||||
struct _GstVideoOverlayCompositionClass
|
||||
{
|
||||
GstMiniObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstVideoOverlayRectangle
|
||||
{
|
||||
GstMiniObject parent;
|
||||
|
@ -155,19 +150,9 @@ struct _GstVideoOverlayRectangle
|
|||
GList *scaled_rectangles;
|
||||
};
|
||||
|
||||
struct _GstVideoOverlayRectangleClass
|
||||
{
|
||||
GstMiniObjectClass parent_class;
|
||||
};
|
||||
|
||||
#define GST_RECTANGLE_LOCK(rect) g_mutex_lock(&rect->lock)
|
||||
#define GST_RECTANGLE_UNLOCK(rect) g_mutex_unlock(&rect->lock)
|
||||
|
||||
static void gst_video_overlay_composition_class_init (GstMiniObjectClass * k);
|
||||
static void gst_video_overlay_composition_finalize (GstMiniObject * comp);
|
||||
static void gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass);
|
||||
static void gst_video_overlay_rectangle_finalize (GstMiniObject * rect);
|
||||
|
||||
/* --------------------------- utility functions --------------------------- */
|
||||
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
|
@ -205,38 +190,114 @@ gst_video_overlay_get_seqnum (void)
|
|||
return (guint) g_atomic_int_add (&seqnum, 1);
|
||||
}
|
||||
|
||||
#define GST_OVERLAY_COMPOSITION_QUARK gst_overlay_composition_quark_get()
|
||||
static GQuark
|
||||
gst_overlay_composition_quark_get (void)
|
||||
/* TODO ??
|
||||
* maybe this should be in public header and expose a more meta oriented API,
|
||||
* rather than hiding it here internally ? */
|
||||
|
||||
#define GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE \
|
||||
(gst_video_overlay_composition_meta_api_get_type())
|
||||
#define GST_VIDEO_OVERLAY_COMPOSITION_META_INFO \
|
||||
(gst_video_overlay_composition_meta_get_info())
|
||||
typedef struct _GstVideoOverlayCompositionMeta GstVideoOverlayCompositionMeta;
|
||||
|
||||
static const GstMetaInfo *gst_video_overlay_composition_meta_get_info (void);
|
||||
|
||||
/**
|
||||
* GstVideoOverlayCompositionMeta:
|
||||
* @meta: parent #GstMeta
|
||||
* @overlay: the attached #GstVideoOverlayComposition
|
||||
*
|
||||
* Extra buffer metadata describing image overlay data.
|
||||
*/
|
||||
struct _GstVideoOverlayCompositionMeta
|
||||
{
|
||||
static gsize quark_gonce = 0;
|
||||
GstMeta meta;
|
||||
|
||||
if (g_once_init_enter (&quark_gonce)) {
|
||||
gsize quark;
|
||||
GstVideoOverlayComposition *overlay;
|
||||
};
|
||||
|
||||
quark = (gsize) g_quark_from_static_string ("GstVideoOverlayComposition");
|
||||
static void
|
||||
gst_video_overlay_composition_meta_free (GstMeta * meta, GstBuffer * buf)
|
||||
{
|
||||
GstVideoOverlayCompositionMeta *ometa;
|
||||
|
||||
g_once_init_leave (&quark_gonce, quark);
|
||||
}
|
||||
ometa = (GstVideoOverlayCompositionMeta *) meta;
|
||||
|
||||
return (GQuark) quark_gonce;
|
||||
if (ometa->overlay)
|
||||
gst_video_overlay_composition_unref (ometa->overlay);
|
||||
}
|
||||
|
||||
#define COMPOSITION_QUARK composition_quark_get()
|
||||
static GQuark
|
||||
composition_quark_get (void)
|
||||
static gboolean
|
||||
gst_video_overlay_composition_meta_transform (GstBuffer * dest, GstMeta * meta,
|
||||
GstBuffer * buffer, GQuark type, gpointer data)
|
||||
{
|
||||
static gsize quark_gonce = 0;
|
||||
GstVideoOverlayCompositionMeta *dmeta, *smeta;
|
||||
|
||||
if (g_once_init_enter (&quark_gonce)) {
|
||||
gsize quark;
|
||||
smeta = (GstVideoOverlayCompositionMeta *) meta;
|
||||
|
||||
quark = (gsize) g_quark_from_static_string ("composition");
|
||||
if (GST_META_TRANSFORM_IS_COPY (type)) {
|
||||
GstMetaTransformCopy *copy = data;
|
||||
|
||||
g_once_init_leave (&quark_gonce, quark);
|
||||
if (!copy->region) {
|
||||
GST_DEBUG ("copy video overlay composition metadata");
|
||||
|
||||
/* only copy if the complete data is copied as well */
|
||||
dmeta =
|
||||
(GstVideoOverlayCompositionMeta *) gst_buffer_add_meta (dest,
|
||||
GST_VIDEO_OVERLAY_COMPOSITION_META_INFO, NULL);
|
||||
dmeta->overlay = gst_video_overlay_composition_ref (smeta->overlay);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return (GQuark) quark_gonce;
|
||||
static GType
|
||||
gst_video_overlay_composition_meta_api_get_type (void)
|
||||
{
|
||||
static volatile GType type = 0;
|
||||
static const gchar *tags[] = { NULL };
|
||||
|
||||
if (g_once_init_enter (&type)) {
|
||||
GType _type =
|
||||
gst_meta_api_type_register ("GstVideoOverlayCompositionMetaAPI", tags);
|
||||
g_once_init_leave (&type, _type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/* video overlay composition metadata */
|
||||
static const GstMetaInfo *
|
||||
gst_video_overlay_composition_meta_get_info (void)
|
||||
{
|
||||
static const GstMetaInfo *video_overlay_composition_meta_info = NULL;
|
||||
|
||||
if (video_overlay_composition_meta_info == NULL) {
|
||||
video_overlay_composition_meta_info =
|
||||
gst_meta_register (GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE,
|
||||
"GstVideoOverlayCompositionMeta",
|
||||
sizeof (GstVideoOverlayCompositionMeta), (GstMetaInitFunction) NULL,
|
||||
(GstMetaFreeFunction) gst_video_overlay_composition_meta_free,
|
||||
(GstMetaTransformFunction)
|
||||
gst_video_overlay_composition_meta_transform);
|
||||
}
|
||||
return video_overlay_composition_meta_info;
|
||||
}
|
||||
|
||||
static GstVideoOverlayCompositionMeta *
|
||||
gst_video_buffer_get_overlay_composition_meta (GstBuffer * buf)
|
||||
{
|
||||
gpointer state = NULL;
|
||||
GstMeta *meta;
|
||||
const GstMetaInfo *info = GST_VIDEO_OVERLAY_COMPOSITION_META_INFO;
|
||||
|
||||
while ((meta = gst_buffer_iterate_meta (buf, &state))) {
|
||||
if (meta->info->api == info->api) {
|
||||
GstVideoOverlayCompositionMeta *ometa =
|
||||
(GstVideoOverlayCompositionMeta *) meta;
|
||||
return ometa;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,15 +310,26 @@ composition_quark_get (void)
|
|||
* reference to the composition, meaning this function does not take ownership
|
||||
* of @comp.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
void
|
||||
gst_video_buffer_set_overlay_composition (GstBuffer * buf,
|
||||
GstVideoOverlayComposition * comp)
|
||||
{
|
||||
gst_buffer_set_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK,
|
||||
gst_structure_id_new (GST_OVERLAY_COMPOSITION_QUARK,
|
||||
COMPOSITION_QUARK, GST_TYPE_VIDEO_OVERLAY_COMPOSITION, comp, NULL));
|
||||
/* FIXME MT safety ? */
|
||||
|
||||
GstVideoOverlayCompositionMeta *ometa;
|
||||
|
||||
ometa = gst_video_buffer_get_overlay_composition_meta (buf);
|
||||
if (ometa) {
|
||||
gst_mini_object_replace ((GstMiniObject **) & ometa->overlay,
|
||||
(GstMiniObject *) comp);
|
||||
} else {
|
||||
ometa = (GstVideoOverlayCompositionMeta *)
|
||||
gst_buffer_add_meta (buf, GST_VIDEO_OVERLAY_COMPOSITION_META_INFO,
|
||||
NULL);
|
||||
ometa->overlay = comp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,51 +345,28 @@ gst_video_buffer_set_overlay_composition (GstBuffer * buf,
|
|||
* caller must obtain her own ref via gst_video_overlay_composition_ref()
|
||||
* if needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayComposition *
|
||||
gst_video_buffer_get_overlay_composition (GstBuffer * buf)
|
||||
{
|
||||
const GstStructure *s;
|
||||
const GValue *val;
|
||||
GstVideoOverlayCompositionMeta *ometa;
|
||||
|
||||
s = gst_buffer_get_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
val = gst_structure_id_get_value (s, COMPOSITION_QUARK);
|
||||
if (val == NULL)
|
||||
return NULL;
|
||||
|
||||
return GST_VIDEO_OVERLAY_COMPOSITION (gst_value_get_mini_object (val));
|
||||
ometa = gst_video_buffer_get_overlay_composition_meta (buf);
|
||||
if (ometa)
|
||||
return ometa->overlay;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------ composition ------------------------------ */
|
||||
|
||||
#define RECTANGLE_ARRAY_STEP 4 /* premature optimization */
|
||||
|
||||
GType
|
||||
gst_video_overlay_composition_get_type (void)
|
||||
{
|
||||
static volatile gsize type_id = 0;
|
||||
|
||||
if (g_once_init_enter (&type_id)) {
|
||||
GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
|
||||
g_intern_static_string ("GstVideoOverlayComposition"),
|
||||
sizeof (GstVideoOverlayCompositionClass),
|
||||
(GClassInitFunc) gst_video_overlay_composition_class_init,
|
||||
sizeof (GstVideoOverlayComposition),
|
||||
NULL,
|
||||
(GTypeFlags) 0);
|
||||
|
||||
g_once_init_leave (&type_id, new_type_id);
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayComposition,
|
||||
gst_video_overlay_composition);
|
||||
|
||||
static void
|
||||
gst_video_overlay_composition_finalize (GstMiniObject * mini_obj)
|
||||
gst_video_overlay_composition_free (GstMiniObject * mini_obj)
|
||||
{
|
||||
GstVideoOverlayComposition *comp = (GstVideoOverlayComposition *) mini_obj;
|
||||
guint num;
|
||||
|
@ -333,14 +382,7 @@ gst_video_overlay_composition_finalize (GstMiniObject * mini_obj)
|
|||
comp->rectangles = NULL;
|
||||
comp->num_rectangles = 0;
|
||||
|
||||
/* not chaining up to GstMiniObject's finalize for now, we know it's empty */
|
||||
}
|
||||
|
||||
static void
|
||||
gst_video_overlay_composition_class_init (GstMiniObjectClass * klass)
|
||||
{
|
||||
klass->finalize = gst_video_overlay_composition_finalize;
|
||||
klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_composition_copy;
|
||||
g_slice_free (GstVideoOverlayComposition, comp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,7 +396,7 @@ gst_video_overlay_composition_class_init (GstMiniObjectClass * klass)
|
|||
* Returns: (transfer full): a new #GstVideoOverlayComposition. Unref with
|
||||
* gst_video_overlay_composition_unref() when no longer needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayComposition *
|
||||
gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
|
||||
|
@ -367,8 +409,12 @@ gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
|
|||
* an empty new + _add() in a loop is easier? */
|
||||
g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
|
||||
|
||||
comp = (GstVideoOverlayComposition *)
|
||||
gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_COMPOSITION);
|
||||
comp = (GstVideoOverlayComposition *) g_slice_new0 (GstVideoOverlayRectangle);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (comp),
|
||||
GST_TYPE_VIDEO_OVERLAY_COMPOSITION,
|
||||
(GstMiniObjectCopyFunction) gst_video_overlay_composition_copy,
|
||||
NULL, (GstMiniObjectFreeFunction) gst_video_overlay_composition_free);
|
||||
|
||||
comp->rectangles = g_new0 (GstVideoOverlayRectangle *, RECTANGLE_ARRAY_STEP);
|
||||
comp->rectangles[0] = gst_video_overlay_rectangle_ref (rectangle);
|
||||
|
@ -394,7 +440,7 @@ gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
|
|||
* Adds an overlay rectangle to an existing overlay composition object. This
|
||||
* must be done right after creating the overlay composition.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
void
|
||||
gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
|
||||
|
@ -427,7 +473,7 @@ gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
|
|||
*
|
||||
* Returns: the number of rectangles
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
guint
|
||||
gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
|
||||
|
@ -449,7 +495,7 @@ gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
|
|||
* obtain her own reference using gst_video_overlay_rectangle_ref()
|
||||
* if needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayRectangle *
|
||||
gst_video_overlay_composition_get_rectangle (GstVideoOverlayComposition * comp,
|
||||
|
@ -472,40 +518,33 @@ gst_video_overlay_rectangle_needs_scaling (GstVideoOverlayRectangle * r)
|
|||
/**
|
||||
* gst_video_overlay_composition_blend:
|
||||
* @comp: a #GstVideoOverlayComposition
|
||||
* @video_buf: a #GstBuffer containing raw video data in a supported format
|
||||
* @video_buf: a #GstVideoFrame containing raw video data in a supported format
|
||||
*
|
||||
* Blends the overlay rectangles in @comp on top of the raw video data
|
||||
* contained in @video_buf. The data in @video_buf must be writable. If
|
||||
* needed, use gst_buffer_make_writable() before calling this function to
|
||||
* ensure a buffer is writable. @video_buf must also have valid raw video
|
||||
* caps set on it.
|
||||
* contained in @video_buf. The data in @video_buf must be writable and
|
||||
* mapped appropriately.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
gboolean
|
||||
gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
|
||||
GstBuffer * video_buf)
|
||||
GstVideoFrame * video_buf)
|
||||
{
|
||||
GstBlendVideoFormatInfo video_info, rectangle_info;
|
||||
GstVideoInfo rectangle_info, scaled_info;
|
||||
GstVideoInfo *vinfo;
|
||||
GstVideoFrame rectangle_frame;
|
||||
GstVideoFormat fmt;
|
||||
GstBuffer *pixels = NULL;
|
||||
gboolean ret = TRUE;
|
||||
guint n, num;
|
||||
int w, h;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), FALSE);
|
||||
g_return_val_if_fail (GST_IS_BUFFER (video_buf), FALSE);
|
||||
g_return_val_if_fail (gst_buffer_is_writable (video_buf), FALSE);
|
||||
g_return_val_if_fail (GST_BUFFER_CAPS (video_buf) != NULL, FALSE);
|
||||
g_return_val_if_fail (video_buf != NULL, FALSE);
|
||||
|
||||
if (!gst_video_format_parse_caps (GST_BUFFER_CAPS (video_buf), &fmt, &w, &h)) {
|
||||
gchar *str = gst_caps_to_string (GST_BUFFER_CAPS (video_buf));
|
||||
g_warning ("%s: could not parse video buffer caps '%s'", GST_FUNCTION, str);
|
||||
g_free (str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
video_blend_format_info_init (&video_info, GST_BUFFER_DATA (video_buf),
|
||||
h, w, fmt, FALSE);
|
||||
w = GST_VIDEO_FRAME_WIDTH (video_buf);
|
||||
h = GST_VIDEO_FRAME_HEIGHT (video_buf);
|
||||
fmt = GST_VIDEO_FRAME_FORMAT (video_buf);
|
||||
|
||||
num = comp->num_rectangles;
|
||||
GST_LOG ("Blending composition %p with %u rectangles onto video buffer %p "
|
||||
|
@ -520,26 +559,33 @@ gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
|
|||
GST_LOG (" rectangle %u %p: %ux%u, format %u", n, rect, rect->height,
|
||||
rect->width, rect->format);
|
||||
|
||||
video_blend_format_info_init (&rectangle_info,
|
||||
GST_BUFFER_DATA (rect->pixels), rect->height, rect->width,
|
||||
rect->format,
|
||||
! !(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
|
||||
gst_video_info_init (&rectangle_info);
|
||||
gst_video_info_set_format (&rectangle_info, rect->format, rect->width,
|
||||
rect->height);
|
||||
if (rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
|
||||
rectangle_info.flags |= GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||
|
||||
needs_scaling = gst_video_overlay_rectangle_needs_scaling (rect);
|
||||
if (needs_scaling) {
|
||||
video_blend_scale_linear_RGBA (&rectangle_info, rect->render_height,
|
||||
rect->render_width);
|
||||
gst_video_blend_scale_linear_RGBA (&rectangle_info, rect->pixels,
|
||||
rect->render_height, rect->render_width, &scaled_info, &pixels);
|
||||
vinfo = &scaled_info;
|
||||
} else {
|
||||
pixels = gst_buffer_ref (rect->pixels);
|
||||
vinfo = &rectangle_info;
|
||||
}
|
||||
|
||||
ret = video_blend (&video_info, &rectangle_info, rect->x, rect->y,
|
||||
gst_video_frame_map (&rectangle_frame, vinfo, pixels, GST_MAP_READ);
|
||||
|
||||
ret = gst_video_blend (video_buf, &rectangle_frame, rect->x, rect->y,
|
||||
rect->global_alpha);
|
||||
gst_video_frame_unmap (&rectangle_frame);
|
||||
if (!ret) {
|
||||
GST_WARNING ("Could not blend overlay rectangle onto video buffer");
|
||||
}
|
||||
|
||||
/* FIXME: should cache scaled pixels in the rectangle struct */
|
||||
if (needs_scaling)
|
||||
g_free (rectangle_info.pixels);
|
||||
gst_buffer_unref (pixels);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -558,7 +604,7 @@ gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
|
|||
* Returns: (transfer full): a new #GstVideoOverlayComposition equivalent
|
||||
* to @comp.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayComposition *
|
||||
gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
|
||||
|
@ -598,7 +644,7 @@ gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
|
|||
* Returns: (transfer full): a writable #GstVideoOverlayComposition
|
||||
* equivalent to @comp.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayComposition *
|
||||
gst_video_overlay_composition_make_writable (GstVideoOverlayComposition * comp)
|
||||
|
@ -636,7 +682,7 @@ copy:
|
|||
*
|
||||
* Returns: the sequence number of @comp
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
guint
|
||||
gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
|
||||
|
@ -648,30 +694,11 @@ gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
|
|||
|
||||
/* ------------------------------ rectangles ------------------------------ -*/
|
||||
|
||||
static void gst_video_overlay_rectangle_instance_init (GstMiniObject * miniobj);
|
||||
|
||||
GType
|
||||
gst_video_overlay_rectangle_get_type (void)
|
||||
{
|
||||
static volatile gsize type_id = 0;
|
||||
|
||||
if (g_once_init_enter (&type_id)) {
|
||||
GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
|
||||
g_intern_static_string ("GstVideoOverlayRectangle"),
|
||||
sizeof (GstVideoOverlayRectangleClass),
|
||||
(GClassInitFunc) gst_video_overlay_rectangle_class_init,
|
||||
sizeof (GstVideoOverlayRectangle),
|
||||
(GInstanceInitFunc) gst_video_overlay_rectangle_instance_init,
|
||||
(GTypeFlags) 0);
|
||||
|
||||
g_once_init_leave (&type_id, new_type_id);
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayRectangle,
|
||||
gst_video_overlay_rectangle);
|
||||
|
||||
static void
|
||||
gst_video_overlay_rectangle_finalize (GstMiniObject * mini_obj)
|
||||
gst_video_overlay_rectangle_free (GstMiniObject * mini_obj)
|
||||
{
|
||||
GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
|
||||
|
||||
|
@ -689,22 +716,7 @@ gst_video_overlay_rectangle_finalize (GstMiniObject * mini_obj)
|
|||
g_free (rect->initial_alpha);
|
||||
g_mutex_clear (&rect->lock);
|
||||
|
||||
/* not chaining up to GstMiniObject's finalize for now, we know it's empty */
|
||||
}
|
||||
|
||||
static void
|
||||
gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass)
|
||||
{
|
||||
klass->finalize = gst_video_overlay_rectangle_finalize;
|
||||
klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_video_overlay_rectangle_instance_init (GstMiniObject * mini_obj)
|
||||
{
|
||||
GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
|
||||
|
||||
g_mutex_init (&rect->lock);
|
||||
g_slice_free (GstVideoOverlayRectangle, rect);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
|
@ -751,7 +763,7 @@ gst_video_overlay_rectangle_is_same_alpha_type (GstVideoOverlayFormatFlags
|
|||
* Returns: (transfer full): a new #GstVideoOverlayRectangle. Unref with
|
||||
* gst_video_overlay_rectangle_unref() when no longer needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayRectangle *
|
||||
gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
|
||||
|
@ -762,14 +774,20 @@ gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
|
|||
|
||||
g_return_val_if_fail (GST_IS_BUFFER (pixels), NULL);
|
||||
/* technically ((height-1)*stride)+width might be okay too */
|
||||
g_return_val_if_fail (GST_BUFFER_SIZE (pixels) >= height * stride, NULL);
|
||||
g_return_val_if_fail (gst_buffer_get_size (pixels) >= height * stride, NULL);
|
||||
g_return_val_if_fail (stride >= (4 * width), NULL);
|
||||
g_return_val_if_fail (height > 0 && width > 0, NULL);
|
||||
g_return_val_if_fail (render_height > 0 && render_width > 0, NULL);
|
||||
g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
|
||||
|
||||
rect = (GstVideoOverlayRectangle *)
|
||||
gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_RECTANGLE);
|
||||
rect = (GstVideoOverlayRectangle *) g_slice_new0 (GstVideoOverlayRectangle);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (rect),
|
||||
GST_TYPE_VIDEO_OVERLAY_RECTANGLE,
|
||||
(GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy,
|
||||
NULL, (GstMiniObjectFreeFunction) gst_video_overlay_rectangle_free);
|
||||
|
||||
g_mutex_init (&rect->lock);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
rect->format = GST_VIDEO_FORMAT_BGRA;
|
||||
|
@ -778,6 +796,7 @@ gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
|
|||
#endif
|
||||
|
||||
rect->pixels = gst_buffer_ref (pixels);
|
||||
rect->scaled_rectangles = NULL;
|
||||
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
|
@ -817,7 +836,7 @@ gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
|
|||
*
|
||||
* Returns: TRUE if valid render dimensions were retrieved.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
gboolean
|
||||
gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
|
||||
|
@ -856,7 +875,7 @@ gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
|
|||
* gst_video_overlay_composition_make_writable() or
|
||||
* gst_video_overlay_composition_copy().
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
void
|
||||
gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
|
||||
|
@ -886,12 +905,15 @@ gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
|
|||
|
||||
/* FIXME: orc-ify */
|
||||
static void
|
||||
gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
|
||||
gst_video_overlay_rectangle_premultiply (GstVideoFrame * frame)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < info->height; ++j) {
|
||||
guint8 *line = info->pixels + info->stride[0] * j;
|
||||
for (i = 0; i < info->width; ++i) {
|
||||
for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
|
||||
guint8 *line;
|
||||
|
||||
line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
|
||||
line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
|
||||
for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
|
||||
int a = line[ARGB_A];
|
||||
line[ARGB_R] = line[ARGB_R] * a / 255;
|
||||
line[ARGB_G] = line[ARGB_G] * a / 255;
|
||||
|
@ -903,12 +925,15 @@ gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
|
|||
|
||||
/* FIXME: orc-ify */
|
||||
static void
|
||||
gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
|
||||
gst_video_overlay_rectangle_unpremultiply (GstVideoFrame * frame)
|
||||
{
|
||||
int i, j;
|
||||
for (j = 0; j < info->height; ++j) {
|
||||
guint8 *line = info->pixels + info->stride[0] * j;
|
||||
for (i = 0; i < info->width; ++i) {
|
||||
for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
|
||||
guint8 *line;
|
||||
|
||||
line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
|
||||
line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
|
||||
for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
|
||||
int a = line[ARGB_A];
|
||||
if (a) {
|
||||
line[ARGB_R] = MIN ((line[ARGB_R] * 255 + a / 2) / a, 255);
|
||||
|
@ -927,18 +952,21 @@ gst_video_overlay_rectangle_extract_alpha (GstVideoOverlayRectangle * rect)
|
|||
guint8 *src, *dst;
|
||||
int offset = 0;
|
||||
int alpha_size = rect->stride * rect->height / 4;
|
||||
GstMapInfo map;
|
||||
|
||||
g_free (rect->initial_alpha);
|
||||
rect->initial_alpha = NULL;
|
||||
|
||||
rect->initial_alpha = g_malloc (alpha_size);
|
||||
src = GST_BUFFER_DATA (rect->pixels);
|
||||
gst_buffer_map (rect->pixels, &map, GST_MAP_READ);
|
||||
src = map.data;
|
||||
dst = rect->initial_alpha;
|
||||
/* FIXME we're accessing possibly uninitialised bytes from the row padding */
|
||||
while (offset < alpha_size) {
|
||||
dst[offset] = src[offset * 4 + ARGB_A];
|
||||
++offset;
|
||||
}
|
||||
gst_buffer_unmap (rect->pixels, &map);
|
||||
}
|
||||
|
||||
|
||||
|
@ -948,6 +976,7 @@ gst_video_overlay_rectangle_apply_global_alpha (GstVideoOverlayRectangle * rect,
|
|||
{
|
||||
guint8 *src, *dst;
|
||||
guint offset = 0;
|
||||
GstMapInfo map;
|
||||
|
||||
g_assert (!(rect->applied_global_alpha != 1.0
|
||||
&& rect->initial_alpha == NULL));
|
||||
|
@ -960,7 +989,8 @@ gst_video_overlay_rectangle_apply_global_alpha (GstVideoOverlayRectangle * rect,
|
|||
|
||||
src = rect->initial_alpha;
|
||||
rect->pixels = gst_buffer_make_writable (rect->pixels);
|
||||
dst = GST_BUFFER_DATA (rect->pixels);
|
||||
gst_buffer_map (rect->pixels, &map, GST_MAP_READ);
|
||||
dst = map.data;
|
||||
while (offset < (rect->height * rect->stride / 4)) {
|
||||
guint doff = offset * 4;
|
||||
guint8 na = (guint8) src[offset] * global_alpha;
|
||||
|
@ -978,6 +1008,7 @@ gst_video_overlay_rectangle_apply_global_alpha (GstVideoOverlayRectangle * rect,
|
|||
dst[doff + ARGB_A] = na;
|
||||
++offset;
|
||||
}
|
||||
gst_buffer_unmap (rect->pixels, &map);
|
||||
|
||||
rect->applied_global_alpha = global_alpha;
|
||||
}
|
||||
|
@ -989,7 +1020,8 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
|
|||
{
|
||||
GstVideoOverlayFormatFlags new_flags;
|
||||
GstVideoOverlayRectangle *scaled_rect = NULL;
|
||||
GstBlendVideoFormatInfo info;
|
||||
GstVideoInfo info;
|
||||
GstVideoFrame frame;
|
||||
GstBuffer *buf;
|
||||
GList *l;
|
||||
guint wanted_width = unscaled ? rectangle->width : rectangle->render_width;
|
||||
|
@ -1046,35 +1078,37 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
|
|||
goto done;
|
||||
|
||||
/* not cached yet, do the preprocessing and put the result into our cache */
|
||||
video_blend_format_info_init (&info, GST_BUFFER_DATA (rectangle->pixels),
|
||||
rectangle->height, rectangle->width, rectangle->format,
|
||||
! !(rectangle->flags &
|
||||
GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
|
||||
gst_video_info_init (&info);
|
||||
gst_video_info_set_format (&info, rectangle->format, rectangle->width,
|
||||
rectangle->height);
|
||||
if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
|
||||
info.flags |= GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
|
||||
|
||||
if (wanted_width != rectangle->width || wanted_height != rectangle->height) {
|
||||
GstVideoInfo scaled_info;
|
||||
|
||||
/* we could check the cache for a scaled rect with global_alpha == 1 here */
|
||||
video_blend_scale_linear_RGBA (&info, wanted_height, wanted_width);
|
||||
gst_video_blend_scale_linear_RGBA (&info, rectangle->pixels,
|
||||
wanted_height, wanted_width, &scaled_info, &buf);
|
||||
info = scaled_info;
|
||||
} else {
|
||||
/* if we don't have to scale, we have to modify the alpha values, so we
|
||||
* need to make a copy of the pixel memory (and we take ownership below) */
|
||||
info.pixels = g_memdup (info.pixels, info.size);
|
||||
buf = gst_buffer_copy (rectangle->pixels);
|
||||
}
|
||||
|
||||
new_flags = rectangle->flags;
|
||||
gst_video_frame_map (&frame, &info, buf, GST_MAP_READWRITE);
|
||||
if (!gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags, flags)) {
|
||||
if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
|
||||
gst_video_overlay_rectangle_unpremultiply (&info);
|
||||
gst_video_overlay_rectangle_unpremultiply (&frame);
|
||||
new_flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
|
||||
} else {
|
||||
gst_video_overlay_rectangle_premultiply (&info);
|
||||
gst_video_overlay_rectangle_premultiply (&frame);
|
||||
new_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
GST_BUFFER_DATA (buf) = info.pixels;
|
||||
GST_BUFFER_MALLOCDATA (buf) = info.pixels;
|
||||
GST_BUFFER_SIZE (buf) = info.size;
|
||||
gst_video_frame_unmap (&frame);
|
||||
|
||||
scaled_rect = gst_video_overlay_rectangle_new_argb (buf,
|
||||
wanted_width, wanted_height, info.stride[0],
|
||||
|
@ -1125,7 +1159,7 @@ done:
|
|||
* not return a reference, the caller should obtain a reference of her own
|
||||
* with gst_buffer_ref() if needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
|
||||
|
@ -1159,7 +1193,7 @@ gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
|
|||
* row stride @stride. This function does not return a reference, the caller
|
||||
* should obtain a reference of her own with gst_buffer_ref() if needed.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstBuffer *
|
||||
gst_video_overlay_rectangle_get_pixels_unscaled_argb (GstVideoOverlayRectangle *
|
||||
|
@ -1267,7 +1301,7 @@ gst_video_overlay_rectangle_set_global_alpha (GstVideoOverlayRectangle *
|
|||
* Returns: (transfer full): a new #GstVideoOverlayRectangle equivalent
|
||||
* to @rectangle.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
GstVideoOverlayRectangle *
|
||||
gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
|
||||
|
@ -1308,7 +1342,7 @@ gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
|
|||
*
|
||||
* Returns: the sequence number of @rectangle
|
||||
*
|
||||
* Since: 0.10.36
|
||||
* Since: 0.11.x
|
||||
*/
|
||||
guint
|
||||
gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)
|
||||
|
|
|
@ -37,10 +37,12 @@ G_BEGIN_DECLS
|
|||
*/
|
||||
#define GST_TYPE_VIDEO_OVERLAY_RECTANGLE \
|
||||
(gst_video_overlay_rectangle_get_type ())
|
||||
#define GST_VIDEO_OVERLAY_RECTANGLE_CAST(obj) \
|
||||
((GstVideoOverlayRectangle *)(obj)
|
||||
#define GST_VIDEO_OVERLAY_RECTANGLE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_OVERLAY_RECTANGLE, GstVideoOverlayRectangle))
|
||||
(GST_VIDEO_OVERLAY_RECTANGLE_CAST(obj))
|
||||
#define GST_IS_VIDEO_OVERLAY_RECTANGLE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_OVERLAY_RECTANGLE))
|
||||
(GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_VIDEO_OVERLAY_RECTANGLE))
|
||||
|
||||
typedef struct _GstVideoOverlayRectangle GstVideoOverlayRectangle;
|
||||
typedef struct _GstVideoOverlayRectangleClass GstVideoOverlayRectangleClass;
|
||||
|
@ -158,10 +160,12 @@ void gst_video_overlay_rectangle_set_global_alpha
|
|||
*/
|
||||
#define GST_TYPE_VIDEO_OVERLAY_COMPOSITION \
|
||||
(gst_video_overlay_composition_get_type ())
|
||||
#define GST_VIDEO_OVERLAY_COMPOSITION_CAST(obj) \
|
||||
((GstVideoOverlayComposition *)(obj)
|
||||
#define GST_VIDEO_OVERLAY_COMPOSITION(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_OVERLAY_COMPOSITION, GstVideoOverlayComposition))
|
||||
(GST_VIDEO_OVERLAY_COMPOSITION_CAST(obj))
|
||||
#define GST_IS_VIDEO_OVERLAY_COMPOSITION(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_OVERLAY_COMPOSITION))
|
||||
(GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_VIDEO_OVERLAY_COMPOSITION))
|
||||
|
||||
typedef struct _GstVideoOverlayComposition GstVideoOverlayComposition;
|
||||
typedef struct _GstVideoOverlayCompositionClass GstVideoOverlayCompositionClass;
|
||||
|
@ -231,7 +235,7 @@ guint gst_video_overlay_composition_get_seqnum (GstVid
|
|||
/* blend composition onto raw video buffer */
|
||||
|
||||
gboolean gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
|
||||
GstBuffer * video_buf);
|
||||
GstVideoFrame * video_buf);
|
||||
|
||||
/* attach/retrieve composition from buffers */
|
||||
|
||||
|
|
Loading…
Reference in a new issue