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;
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;
#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);
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);
}
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);
- ensure_debug_category ();
+ 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);
- if (!lookup_getput (&getputdest, dest->fmt))
- goto failed;
+ 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 (&getputsrc, src->fmt))
+ if (!sinfo || !dinfo)
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 (y + src->height > dest->height)
- src->height = dest->height - y;
+ if (x + src_width > dest_width)
+ src_width = dest_width - x;
- 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*/
} 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);
#undef BLENDLOOP
+ tmpdestline -= 4 * x;
+
/* FIXME
* #if G_BYTE_ORDER == LITTLE_ENDIAN
* orc_blend_little (tmpdestline, tmpsrcline, dest->width);
* #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);
* </para>
* </refsect2>
*
- * Since: 0.10.36
+ * Since: 0.11.x
*/
/* TODO:
guint seq_num;
};
-struct _GstVideoOverlayCompositionClass
-{
- GstMiniObjectClass parent_class;
-};
-
struct _GstVideoOverlayRectangle
{
GstMiniObject parent;
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
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;
+}
+
+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;
+}
- return (GQuark) quark_gonce;
+/* 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;
}
/**
* 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;
+ }
}
/**
* 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;
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);
}
/**
* 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)
* 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);
* 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,
*
* Returns: the number of rectangles
*
- * Since: 0.10.36
+ * Since: 0.11.x
*/
guint
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,
/**
* 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);
-
- 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;
- }
+ g_return_val_if_fail (video_buf != NULL, 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 "
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;
* 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)
* 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)
*
* Returns: the sequence number of @comp
*
- * Since: 0.10.36
+ * Since: 0.11.x
*/
guint
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;
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
* 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,
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;
#endif
rect->pixels = gst_buffer_ref (pixels);
+ rect->scaled_rectangles = NULL;
rect->width = width;
rect->height = height;
*
* 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 *
* 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 *
/* 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;
/* 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);
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);
}
{
guint8 *src, *dst;
guint offset = 0;
+ GstMapInfo map;
g_assert (!(rect->applied_global_alpha != 1.0
&& rect->initial_alpha == NULL));
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;
dst[doff + ARGB_A] = na;
++offset;
}
+ gst_buffer_unmap (rect->pixels, &map);
rect->applied_global_alpha = global_alpha;
}
{
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;
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],
* 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 *
* 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 *
* 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)
*
* Returns: the sequence number of @rectangle
*
- * Since: 0.10.36
+ * Since: 0.11.x
*/
guint
gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)