From e94022806ffaff3075d1494a9e0f96ae6791cb47 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Thu, 28 Jun 2012 18:16:20 +0200 Subject: [PATCH] videooverlaycomposition: port to 0.11 ... which also entails porting video-blend Fixes #678384. --- gst-libs/gst/video/Makefile.am | 9 +- gst-libs/gst/video/video-blend.c | 126 +++--- gst-libs/gst/video/video-blend.h | 5 +- .../gst/video/video-overlay-composition.c | 412 ++++++++++-------- .../gst/video/video-overlay-composition.h | 14 +- 5 files changed, 317 insertions(+), 249 deletions(-) diff --git a/gst-libs/gst/video/Makefile.am b/gst-libs/gst/video/Makefile.am index 8d5b850f01..ddaceb6457 100644 --- a/gst-libs/gst/video/Makefile.am +++ b/gst-libs/gst/video/Makefile.am @@ -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) \ diff --git a/gst-libs/gst/video/video-blend.c b/gst-libs/gst/video/video-blend.c index fed516b35b..db1727a9f3 100644 --- a/gst-libs/gst/video/video-blend.c +++ b/gst-libs/gst/video/video-blend.c @@ -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); diff --git a/gst-libs/gst/video/video-blend.h b/gst-libs/gst/video/video-blend.h index d14485a023..715dac9ef6 100644 --- a/gst-libs/gst/video/video-blend.h +++ b/gst-libs/gst/video/video-blend.h @@ -27,8 +27,9 @@ #include #include -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, diff --git a/gst-libs/gst/video/video-overlay-composition.c b/gst-libs/gst/video/video-overlay-composition.c index 5f4bf76d4b..8c941f0ed3 100644 --- a/gst-libs/gst/video/video-overlay-composition.c +++ b/gst-libs/gst/video/video-overlay-composition.c @@ -55,7 +55,7 @@ * * * - * 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) diff --git a/gst-libs/gst/video/video-overlay-composition.h b/gst-libs/gst/video/video-overlay-composition.h index 65538e487c..5edf789f74 100644 --- a/gst-libs/gst/video/video-overlay-composition.h +++ b/gst-libs/gst/video/video-overlay-composition.h @@ -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 */