1 /* GStreamer Video Overlay Composition
2 * Copyright (C) 2011 Intel Corporation
3 * Copyright (C) 2011 Collabora Ltd.
4 * Copyright (C) 2011 Tim-Philipp Müller <tim centricular net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:gstvideooverlaycomposition
24 * @short_description: Video Buffer Overlay Compositions (Subtitles, Logos)
28 * Functions to create and handle overlay compositions on video buffers.
31 * An overlay composition describes one or more overlay rectangles to be
32 * blended on top of a video buffer.
35 * This API serves two main purposes:
38 * it can be used to attach overlay information (subtitles or logos)
39 * to non-raw video buffers such as GL/VAAPI/VDPAU surfaces. The actual
40 * blending of the overlay can then be done by e.g. the video sink that
41 * processes these non-raw buffers.
44 * it can also be used to blend overlay rectangles on top of raw video
45 * buffers, thus consolidating blending functionality for raw video in
48 * Together, this allows existing overlay elements to easily handle raw
49 * and non-raw video as input in without major changes (once the overlays
50 * have been put into a #GstOverlayComposition object anyway) - for raw
51 * video the overlay can just use the blending function to blend the data
52 * on top of the video, and for surface buffers it can just attach them to
53 * the buffer and let the sink render the overlays.
60 * - provide accessors for seq_num and other fields (as needed)
61 * - allow overlay to set/get original pango markup string on/from rectangle
68 #include "video-overlay-composition.h"
69 #include "video-blend.h"
70 #include "gstvideometa.h"
73 struct _GstVideoOverlayComposition
78 GstVideoOverlayRectangle **rectangles;
80 /* lowest rectangle sequence number still used by the upstream
81 * overlay element. This way a renderer maintaining some kind of
82 * rectangles <-> surface cache can know when to free cached
83 * surfaces/rectangles. */
84 guint min_seq_num_used;
86 /* sequence number for the composition (same series as rectangles) */
90 struct _GstVideoOverlayRectangle
94 /* Position on video frame and dimension of output rectangle in
95 * output frame terms (already adjusted for the PAR of the output
96 * frame). x/y can be negative (overlay will be clipped then) */
98 guint render_width, render_height;
100 /* Info on overlay pixels (format, width, height) */
103 /* The flags associated to this rectangle */
104 GstVideoOverlayFormatFlags flags;
106 /* Refcounted blob of memory, no caps or timestamps */
109 /* FIXME: how to express source like text or pango markup?
110 * (just add source type enum + source buffer with data)
112 * FOR 0.10: always send pixel blobs, but attach source data in
113 * addition (reason: if downstream changes, we can't renegotiate
114 * that properly, if we just do a query of supported formats from
115 * the start). Sink will just ignore pixels and use pango markup
116 * from source data if it supports that.
118 * FOR 0.11: overlay should query formats (pango markup, pixels)
119 * supported by downstream and then only send that. We can
120 * renegotiate via the reconfigure event.
123 /* sequence number: useful for backends/renderers/sinks that want
124 * to maintain a cache of rectangles <-> surfaces. The value of
125 * the min_seq_num_used in the composition tells the renderer which
126 * rectangles have expired. */
129 /* global alpha: global alpha value of the rectangle. Each each per-pixel
130 * alpha value of image-data will be multiplied with the global alpha value
132 * Can be used for efficient fading in/out of overlay rectangles.
133 * GstElements that render OverlayCompositions and don't support global alpha
134 * should simply ignore it.*/
137 /* track alpha-values already applied: */
138 gfloat applied_global_alpha;
139 /* store initial per-pixel alpha values: */
140 guint8 *initial_alpha;
142 /* FIXME: we may also need a (private) way to cache converted/scaled
146 GList *scaled_rectangles;
149 #define GST_RECTANGLE_LOCK(rect) g_mutex_lock(&rect->lock)
150 #define GST_RECTANGLE_UNLOCK(rect) g_mutex_unlock(&rect->lock)
152 /* --------------------------- utility functions --------------------------- */
154 #ifndef GST_DISABLE_GST_DEBUG
156 #define GST_CAT_DEFAULT ensure_debug_category()
158 static GstDebugCategory *
159 ensure_debug_category (void)
161 static gsize cat_gonce = 0;
163 if (g_once_init_enter (&cat_gonce)) {
166 cat_done = (gsize) _gst_debug_category_new ("video-composition", 0,
167 "video overlay composition");
169 g_once_init_leave (&cat_gonce, cat_done);
172 return (GstDebugCategory *) cat_gonce;
177 #define ensure_debug_category() /* NOOP */
179 #endif /* GST_DISABLE_GST_DEBUG */
182 gst_video_overlay_get_seqnum (void)
184 static gint seqnum; /* 0 */
186 return (guint) g_atomic_int_add (&seqnum, 1);
190 gst_video_overlay_composition_meta_free (GstMeta * meta, GstBuffer * buf)
192 GstVideoOverlayCompositionMeta *ometa;
194 ometa = (GstVideoOverlayCompositionMeta *) meta;
197 gst_video_overlay_composition_unref (ometa->overlay);
201 gst_video_overlay_composition_meta_transform (GstBuffer * dest, GstMeta * meta,
202 GstBuffer * buffer, GQuark type, gpointer data)
204 GstVideoOverlayCompositionMeta *dmeta, *smeta;
206 smeta = (GstVideoOverlayCompositionMeta *) meta;
208 if (GST_META_TRANSFORM_IS_COPY (type)) {
209 GstMetaTransformCopy *copy = data;
212 GST_DEBUG ("copy video overlay composition metadata");
214 /* only copy if the complete data is copied as well */
216 (GstVideoOverlayCompositionMeta *) gst_buffer_add_meta (dest,
217 GST_VIDEO_OVERLAY_COMPOSITION_META_INFO, NULL);
218 dmeta->overlay = gst_video_overlay_composition_ref (smeta->overlay);
225 gst_video_overlay_composition_meta_api_get_type (void)
227 static volatile GType type = 0;
228 static const gchar *tags[] = { NULL };
230 if (g_once_init_enter (&type)) {
232 gst_meta_api_type_register ("GstVideoOverlayCompositionMetaAPI", tags);
233 g_once_init_leave (&type, _type);
238 /* video overlay composition metadata */
240 gst_video_overlay_composition_meta_get_info (void)
242 static const GstMetaInfo *video_overlay_composition_meta_info = NULL;
244 if (g_once_init_enter (&video_overlay_composition_meta_info)) {
245 const GstMetaInfo *meta =
246 gst_meta_register (GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE,
247 "GstVideoOverlayCompositionMeta",
248 sizeof (GstVideoOverlayCompositionMeta), (GstMetaInitFunction) NULL,
249 (GstMetaFreeFunction) gst_video_overlay_composition_meta_free,
250 (GstMetaTransformFunction)
251 gst_video_overlay_composition_meta_transform);
252 g_once_init_leave (&video_overlay_composition_meta_info, meta);
254 return video_overlay_composition_meta_info;
258 * gst_buffer_add_video_overlay_composition_meta:
260 * @comp: (allow-none): a #GstVideoOverlayComposition
262 * Sets an overlay composition on a buffer. The buffer will obtain its own
263 * reference to the composition, meaning this function does not take ownership
266 GstVideoOverlayCompositionMeta *
267 gst_buffer_add_video_overlay_composition_meta (GstBuffer * buf,
268 GstVideoOverlayComposition * comp)
270 GstVideoOverlayCompositionMeta *ometa;
272 g_return_val_if_fail (gst_buffer_is_writable (buf), NULL);
274 ometa = (GstVideoOverlayCompositionMeta *)
275 gst_buffer_add_meta (buf, GST_VIDEO_OVERLAY_COMPOSITION_META_INFO, NULL);
277 ometa->overlay = gst_video_overlay_composition_ref (comp);
282 /* ------------------------------ composition ------------------------------ */
284 #define RECTANGLE_ARRAY_STEP 4 /* premature optimization */
286 GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayComposition,
287 gst_video_overlay_composition);
290 gst_video_overlay_composition_free (GstMiniObject * mini_obj)
292 GstVideoOverlayComposition *comp = (GstVideoOverlayComposition *) mini_obj;
295 num = comp->num_rectangles;
298 gst_video_overlay_rectangle_unref (comp->rectangles[num - 1]);
302 g_free (comp->rectangles);
303 comp->rectangles = NULL;
304 comp->num_rectangles = 0;
306 g_slice_free (GstVideoOverlayComposition, comp);
310 * gst_video_overlay_composition_new:
311 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
314 * Creates a new video overlay composition object to hold one or more
315 * overlay rectangles.
317 * Returns: (transfer full): a new #GstVideoOverlayComposition. Unref with
318 * gst_video_overlay_composition_unref() when no longer needed.
320 GstVideoOverlayComposition *
321 gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
323 GstVideoOverlayComposition *comp;
326 /* FIXME: should we allow empty compositions? Could also be expressed as
327 * buffer without a composition on it. Maybe there are cases where doing
328 * an empty new + _add() in a loop is easier? */
329 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
331 comp = g_slice_new0 (GstVideoOverlayComposition);
333 gst_mini_object_init (GST_MINI_OBJECT_CAST (comp), 0,
334 GST_TYPE_VIDEO_OVERLAY_COMPOSITION,
335 (GstMiniObjectCopyFunction) gst_video_overlay_composition_copy,
336 NULL, (GstMiniObjectFreeFunction) gst_video_overlay_composition_free);
338 comp->rectangles = g_new0 (GstVideoOverlayRectangle *, RECTANGLE_ARRAY_STEP);
339 comp->rectangles[0] = gst_video_overlay_rectangle_ref (rectangle);
340 comp->num_rectangles = 1;
342 comp->seq_num = gst_video_overlay_get_seqnum ();
344 /* since the rectangle was created earlier, its seqnum is smaller than ours */
345 comp->min_seq_num_used = rectangle->seq_num;
347 GST_LOG ("new composition %p: seq_num %u with rectangle %p", comp,
348 comp->seq_num, rectangle);
354 * gst_video_overlay_composition_add_rectangle:
355 * @comp: a #GstVideoOverlayComposition
356 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
359 * Adds an overlay rectangle to an existing overlay composition object. This
360 * must be done right after creating the overlay composition.
363 gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
364 GstVideoOverlayRectangle * rectangle)
366 g_return_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp));
367 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
368 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1);
370 if (comp->num_rectangles % RECTANGLE_ARRAY_STEP == 0) {
372 g_renew (GstVideoOverlayRectangle *, comp->rectangles,
373 comp->num_rectangles + RECTANGLE_ARRAY_STEP);
376 comp->rectangles[comp->num_rectangles] =
377 gst_video_overlay_rectangle_ref (rectangle);
378 comp->num_rectangles += 1;
380 comp->min_seq_num_used = MIN (comp->min_seq_num_used, rectangle->seq_num);
382 GST_LOG ("composition %p: added rectangle %p", comp, rectangle);
386 * gst_video_overlay_composition_n_rectangles:
387 * @comp: a #GstVideoOverlayComposition
389 * Returns the number of #GstVideoOverlayRectangle<!-- -->s contained in @comp.
391 * Returns: the number of rectangles
394 gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
396 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
398 return comp->num_rectangles;
402 * gst_video_overlay_composition_get_rectangle:
403 * @comp: a #GstVideoOverlayComposition
404 * @n: number of the rectangle to get
406 * Returns the @n-th #GstVideoOverlayRectangle contained in @comp.
408 * Returns: (transfer none): the @n-th rectangle, or NULL if @n is out of
409 * bounds. Will not return a new reference, the caller will need to
410 * obtain her own reference using gst_video_overlay_rectangle_ref()
413 GstVideoOverlayRectangle *
414 gst_video_overlay_composition_get_rectangle (GstVideoOverlayComposition * comp,
417 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
419 if (n >= comp->num_rectangles)
422 return comp->rectangles[n];
426 gst_video_overlay_rectangle_needs_scaling (GstVideoOverlayRectangle * r)
428 return (GST_VIDEO_INFO_WIDTH (&r->info) != r->render_width ||
429 GST_VIDEO_INFO_HEIGHT (&r->info) != r->render_height);
433 * gst_video_overlay_composition_blend:
434 * @comp: a #GstVideoOverlayComposition
435 * @video_buf: a #GstVideoFrame containing raw video data in a supported format
437 * Blends the overlay rectangles in @comp on top of the raw video data
438 * contained in @video_buf. The data in @video_buf must be writable and
439 * mapped appropriately.
441 /* FIXME: formats with more than 8 bit per component which get unpacked into
442 * ARGB64 or AYUV64 (such as v210, v216, UYVP, GRAY16_LE and GRAY16_BE)
443 * are not supported yet by the code in video-blend.c.
446 gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
447 GstVideoFrame * video_buf)
449 GstVideoInfo scaled_info;
451 GstVideoFrame rectangle_frame;
453 GstBuffer *pixels = NULL;
458 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), FALSE);
459 g_return_val_if_fail (video_buf != NULL, FALSE);
461 w = GST_VIDEO_FRAME_WIDTH (video_buf);
462 h = GST_VIDEO_FRAME_HEIGHT (video_buf);
463 fmt = GST_VIDEO_FRAME_FORMAT (video_buf);
465 num = comp->num_rectangles;
466 GST_LOG ("Blending composition %p with %u rectangles onto video buffer %p "
467 "(%ux%u, format %u)", comp, num, video_buf, w, h, fmt);
469 for (n = 0; n < num; ++n) {
470 GstVideoOverlayRectangle *rect;
471 gboolean needs_scaling;
473 rect = comp->rectangles[n];
475 GST_LOG (" rectangle %u %p: %ux%u, format %u", n, rect,
476 GST_VIDEO_INFO_WIDTH (&rect->info), GST_VIDEO_INFO_HEIGHT (&rect->info),
477 GST_VIDEO_INFO_FORMAT (&rect->info));
479 needs_scaling = gst_video_overlay_rectangle_needs_scaling (rect);
481 gst_video_blend_scale_linear_RGBA (&rect->info, rect->pixels,
482 rect->render_height, rect->render_width, &scaled_info, &pixels);
483 vinfo = &scaled_info;
485 pixels = gst_buffer_ref (rect->pixels);
489 gst_video_frame_map (&rectangle_frame, vinfo, pixels, GST_MAP_READ);
491 ret = gst_video_blend (video_buf, &rectangle_frame, rect->x, rect->y,
493 gst_video_frame_unmap (&rectangle_frame);
495 GST_WARNING ("Could not blend overlay rectangle onto video buffer");
498 /* FIXME: should cache scaled pixels in the rectangle struct */
499 gst_buffer_unref (pixels);
506 * gst_video_overlay_composition_copy:
507 * @comp: (transfer none): a #GstVideoOverlayComposition to copy
509 * Makes a copy of @comp and all contained rectangles, so that it is possible
510 * to modify the composition and contained rectangles (e.g. add additional
511 * rectangles or change the render co-ordinates or render dimension). The
512 * actual overlay pixel data buffers contained in the rectangles are not
515 * Returns: (transfer full): a new #GstVideoOverlayComposition equivalent
518 GstVideoOverlayComposition *
519 gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
521 GstVideoOverlayComposition *copy;
522 GstVideoOverlayRectangle *rect;
525 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
527 if (G_LIKELY (comp->num_rectangles == 0))
528 return gst_video_overlay_composition_new (NULL);
530 rect = gst_video_overlay_rectangle_copy (comp->rectangles[0]);
531 copy = gst_video_overlay_composition_new (rect);
532 gst_video_overlay_rectangle_unref (rect);
534 for (n = 1; n < comp->num_rectangles; ++n) {
535 rect = gst_video_overlay_rectangle_copy (comp->rectangles[n]);
536 gst_video_overlay_composition_add_rectangle (copy, rect);
537 gst_video_overlay_rectangle_unref (rect);
544 * gst_video_overlay_composition_make_writable:
545 * @comp: (transfer full): a #GstVideoOverlayComposition to copy
547 * Takes ownership of @comp and returns a version of @comp that is writable
548 * (i.e. can be modified). Will either return @comp right away, or create a
549 * new writable copy of @comp and unref @comp itself. All the contained
550 * rectangles will also be copied, but the actual overlay pixel data buffers
551 * contained in the rectangles are not copied.
553 * Returns: (transfer full): a writable #GstVideoOverlayComposition
554 * equivalent to @comp.
556 GstVideoOverlayComposition *
557 gst_video_overlay_composition_make_writable (GstVideoOverlayComposition * comp)
559 GstVideoOverlayComposition *writable_comp;
561 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
563 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1) {
566 for (n = 0; n < comp->num_rectangles; ++n) {
567 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp->rectangles[n]) != 1)
575 writable_comp = gst_video_overlay_composition_copy (comp);
576 gst_video_overlay_composition_unref (comp);
578 return writable_comp;
582 * gst_video_overlay_composition_get_seqnum:
583 * @comp: a #GstVideoOverlayComposition
585 * Returns the sequence number of this composition. Sequence numbers are
586 * monotonically increasing and unique for overlay compositions and rectangles
587 * (meaning there will never be a rectangle with the same sequence number as
590 * Returns: the sequence number of @comp
593 gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
595 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
597 return comp->seq_num;
600 /* ------------------------------ rectangles ------------------------------ -*/
602 GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayRectangle,
603 gst_video_overlay_rectangle);
606 gst_video_overlay_rectangle_free (GstMiniObject * mini_obj)
608 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
610 gst_buffer_replace (&rect->pixels, NULL);
612 while (rect->scaled_rectangles != NULL) {
613 GstVideoOverlayRectangle *scaled_rect = rect->scaled_rectangles->data;
615 gst_video_overlay_rectangle_unref (scaled_rect);
617 rect->scaled_rectangles =
618 g_list_delete_link (rect->scaled_rectangles, rect->scaled_rectangles);
621 g_free (rect->initial_alpha);
622 g_mutex_clear (&rect->lock);
624 g_slice_free (GstVideoOverlayRectangle, rect);
627 static inline gboolean
628 gst_video_overlay_rectangle_check_flags (GstVideoOverlayFormatFlags flags)
630 /* Check flags only contains flags we know about */
631 return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA |
632 GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)) == 0;
636 gst_video_overlay_rectangle_is_same_alpha_type (GstVideoOverlayFormatFlags
637 flags1, GstVideoOverlayFormatFlags flags2)
639 return ((flags1 ^ flags2) & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
645 * gst_video_overlay_rectangle_new_raw:
646 * @pixels: (transfer none): a #GstBuffer pointing to the pixel memory
647 * @render_x: the X co-ordinate on the video where the top-left corner of this
648 * overlay rectangle should be rendered to
649 * @render_y: the Y co-ordinate on the video where the top-left corner of this
650 * overlay rectangle should be rendered to
651 * @render_width: the render width of this rectangle on the video
652 * @render_height: the render height of this rectangle on the video
655 * Creates a new video overlay rectangle with ARGB or AYUV pixel data.
656 * The layout in case of ARGB of the components in memory is B-G-R-A
657 * on little-endian platforms
658 * (corresponding to #GST_VIDEO_FORMAT_BGRA) and A-R-G-B on big-endian
659 * platforms (corresponding to #GST_VIDEO_FORMAT_ARGB). In other words,
660 * pixels are treated as 32-bit words and the lowest 8 bits then contain
661 * the blue component value and the highest 8 bits contain the alpha
662 * component value. Unless specified in the flags, the RGB values are
663 * non-premultiplied. This is the format that is used by most hardware,
664 * and also many rendering libraries such as Cairo, for example.
665 * The pixel data buffer must have #GstVideoMeta set.
667 * Returns: (transfer full): a new #GstVideoOverlayRectangle. Unref with
668 * gst_video_overlay_rectangle_unref() when no longer needed.
670 GstVideoOverlayRectangle *
671 gst_video_overlay_rectangle_new_raw (GstBuffer * pixels,
672 gint render_x, gint render_y, guint render_width, guint render_height,
673 GstVideoOverlayFormatFlags flags)
675 GstVideoOverlayRectangle *rect;
677 GstVideoFormat format;
680 g_return_val_if_fail (GST_IS_BUFFER (pixels), NULL);
681 g_return_val_if_fail (render_height > 0 && render_width > 0, NULL);
682 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
684 /* buffer must have video meta with some expected settings */
685 vmeta = gst_buffer_get_video_meta (pixels);
686 g_return_val_if_fail (vmeta, NULL);
687 g_return_val_if_fail (vmeta->format ==
688 GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB ||
689 vmeta->format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV, NULL);
690 g_return_val_if_fail (vmeta->flags == GST_VIDEO_FRAME_FLAG_NONE, NULL);
692 format = vmeta->format;
693 width = vmeta->width;
694 height = vmeta->height;
696 /* technically ((height-1)*stride)+width might be okay too */
697 g_return_val_if_fail (gst_buffer_get_size (pixels) >= height * width * 4,
699 g_return_val_if_fail (height > 0 && width > 0, NULL);
701 rect = g_slice_new0 (GstVideoOverlayRectangle);
703 gst_mini_object_init (GST_MINI_OBJECT_CAST (rect), 0,
704 GST_TYPE_VIDEO_OVERLAY_RECTANGLE,
705 (GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy,
706 NULL, (GstMiniObjectFreeFunction) gst_video_overlay_rectangle_free);
708 g_mutex_init (&rect->lock);
710 rect->pixels = gst_buffer_ref (pixels);
711 rect->scaled_rectangles = NULL;
713 gst_video_info_init (&rect->info);
714 gst_video_info_set_format (&rect->info, format, width, height);
715 if (flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
716 rect->info.flags |= GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
720 rect->render_width = render_width;
721 rect->render_height = render_height;
723 rect->global_alpha = 1.0;
724 rect->applied_global_alpha = 1.0;
725 rect->initial_alpha = NULL;
729 rect->seq_num = gst_video_overlay_get_seqnum ();
731 GST_LOG ("new rectangle %p: %ux%u => %ux%u @ %u,%u, seq_num %u, format %u, "
732 "flags %x, pixels %p, global_alpha=%f", rect, width, height, render_width,
733 render_height, render_x, render_y, rect->seq_num, format,
734 rect->flags, pixels, rect->global_alpha);
740 * gst_video_overlay_rectangle_get_render_rectangle:
741 * @rectangle: a #GstVideoOverlayRectangle
742 * @render_x: (out) (allow-none): address where to store the X render offset
743 * @render_y: (out) (allow-none): address where to store the Y render offset
744 * @render_width: (out) (allow-none): address where to store the render width
745 * @render_height: (out) (allow-none): address where to store the render height
747 * Retrieves the render position and render dimension of the overlay
748 * rectangle on the video.
750 * Returns: TRUE if valid render dimensions were retrieved.
753 gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
754 rectangle, gint * render_x, gint * render_y, guint * render_width,
755 guint * render_height)
757 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), FALSE);
760 *render_x = rectangle->x;
762 *render_y = rectangle->y;
764 *render_width = rectangle->render_width;
766 *render_height = rectangle->render_height;
772 * gst_video_overlay_rectangle_set_render_rectangle:
773 * @rectangle: a #GstVideoOverlayRectangle
774 * @render_x: render X position of rectangle on video
775 * @render_y: render Y position of rectangle on video
776 * @render_width: render width of rectangle
777 * @render_height: render height of rectangle
779 * Sets the render position and dimensions of the rectangle on the video.
780 * This function is mainly for elements that modify the size of the video
781 * in some way (e.g. through scaling or cropping) and need to adjust the
782 * details of any overlays to match the operation that changed the size.
784 * @rectangle must be writable, meaning its refcount must be 1. You can
785 * make the rectangles inside a #GstVideoOverlayComposition writable using
786 * gst_video_overlay_composition_make_writable() or
787 * gst_video_overlay_composition_copy().
790 gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
791 rectangle, gint render_x, gint render_y, guint render_width,
794 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
795 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (rectangle) == 1);
797 rectangle->x = render_x;
798 rectangle->y = render_y;
799 rectangle->render_width = render_width;
800 rectangle->render_height = render_height;
805 gst_video_overlay_rectangle_premultiply_0 (GstVideoFrame * frame)
808 for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
811 line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
812 line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
813 for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
815 line[1] = line[1] * a / 255;
816 line[2] = line[2] * a / 255;
817 line[3] = line[3] * a / 255;
824 gst_video_overlay_rectangle_premultiply_3 (GstVideoFrame * frame)
827 for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
830 line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
831 line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
832 for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
834 line[0] = line[0] * a / 255;
835 line[1] = line[1] * a / 255;
836 line[2] = line[2] * a / 255;
843 gst_video_overlay_rectangle_premultiply (GstVideoFrame * frame)
847 alpha_offset = GST_VIDEO_FRAME_COMP_POFFSET (frame, 3);
848 switch (alpha_offset) {
850 gst_video_overlay_rectangle_premultiply_0 (frame);
853 gst_video_overlay_rectangle_premultiply_3 (frame);
856 g_assert_not_reached ();
863 gst_video_overlay_rectangle_unpremultiply_0 (GstVideoFrame * frame)
866 for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
869 line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
870 line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
871 for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
874 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
875 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
876 line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
884 gst_video_overlay_rectangle_unpremultiply_3 (GstVideoFrame * frame)
887 for (j = 0; j < GST_VIDEO_FRAME_HEIGHT (frame); ++j) {
890 line = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
891 line += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) * j;
892 for (i = 0; i < GST_VIDEO_FRAME_WIDTH (frame); ++i) {
895 line[0] = MIN ((line[0] * 255 + a / 2) / a, 255);
896 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
897 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
905 gst_video_overlay_rectangle_unpremultiply (GstVideoFrame * frame)
909 alpha_offset = GST_VIDEO_FRAME_COMP_POFFSET (frame, 3);
910 switch (alpha_offset) {
912 gst_video_overlay_rectangle_unpremultiply_0 (frame);
915 gst_video_overlay_rectangle_unpremultiply_3 (frame);
918 g_assert_not_reached ();
925 gst_video_overlay_rectangle_extract_alpha (GstVideoOverlayRectangle * rect)
929 gint i, j, w, h, stride, alpha_offset;
931 alpha_offset = GST_VIDEO_INFO_COMP_POFFSET (&rect->info, 3);
932 g_return_if_fail (alpha_offset == 0 || alpha_offset == 3);
934 gst_video_frame_map (&frame, &rect->info, rect->pixels, GST_MAP_READ);
935 src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
936 w = GST_VIDEO_INFO_WIDTH (&rect->info);
937 h = GST_VIDEO_INFO_HEIGHT (&rect->info);
938 stride = GST_VIDEO_INFO_PLANE_STRIDE (&rect->info, 0);
940 g_free (rect->initial_alpha);
941 rect->initial_alpha = g_malloc (w * h);
942 dst = rect->initial_alpha;
944 for (i = 0; i < h; i++) {
945 for (j = 0; j < w; j++) {
946 *dst = src[alpha_offset];
950 src += stride - 4 * w;
952 gst_video_frame_unmap (&frame);
957 gst_video_overlay_rectangle_apply_global_alpha (GstVideoOverlayRectangle * rect,
962 gint i, j, w, h, stride;
963 gint argb_a, argb_r, argb_g, argb_b;
965 g_assert (!(rect->applied_global_alpha != 1.0
966 && rect->initial_alpha == NULL));
968 if (global_alpha == rect->applied_global_alpha)
971 if (rect->initial_alpha == NULL)
972 gst_video_overlay_rectangle_extract_alpha (rect);
974 src = rect->initial_alpha;
975 rect->pixels = gst_buffer_make_writable (rect->pixels);
977 gst_video_frame_map (&frame, &rect->info, rect->pixels, GST_MAP_READ);
978 dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
979 w = GST_VIDEO_INFO_WIDTH (&rect->info);
980 h = GST_VIDEO_INFO_HEIGHT (&rect->info);
981 stride = GST_VIDEO_INFO_PLANE_STRIDE (&rect->info, 0);
983 argb_a = GST_VIDEO_INFO_COMP_POFFSET (&rect->info, 3);
984 argb_r = (argb_a + 1) % 4;
985 argb_g = (argb_a + 2) % 4;
986 argb_b = (argb_a + 3) % 4;
988 for (i = 0; i < h; i++) {
989 for (j = 0; j < w; j++) {
990 guint8 na = (guint8) (*src * global_alpha);
992 if (! !(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) {
994 (guint8) ((double) (dst[argb_r] * 255) / (double) dst[argb_a]) *
997 (guint8) ((double) (dst[argb_g] * 255) / (double) dst[argb_a]) *
1000 (guint8) ((double) (dst[argb_b] * 255) / (double) dst[argb_a]) *
1007 dst += stride - 4 * w;
1009 gst_video_frame_unmap (&frame);
1011 rect->applied_global_alpha = global_alpha;
1015 gst_video_overlay_rectangle_convert (GstVideoInfo * src, GstBuffer * src_buffer,
1016 GstVideoFormat dest_format, GstVideoInfo * dest, GstBuffer ** dest_buffer)
1018 gint width, height, stride;
1019 GstVideoFrame src_frame, dest_frame;
1020 GstVideoFormat format;
1022 guint8 *sdata, *ddata;
1024 format = GST_VIDEO_INFO_FORMAT (src);
1026 width = GST_VIDEO_INFO_WIDTH (src);
1027 height = GST_VIDEO_INFO_HEIGHT (src);
1029 gst_video_info_init (dest);
1030 gst_video_info_set_format (dest, dest_format, width, height);
1032 *dest_buffer = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (dest));
1034 gst_video_frame_map (&src_frame, src, src_buffer, GST_MAP_READ);
1035 gst_video_frame_map (&dest_frame, dest, *dest_buffer, GST_MAP_WRITE);
1037 sdata = GST_VIDEO_FRAME_PLANE_DATA (&src_frame, 0);
1038 ddata = GST_VIDEO_FRAME_PLANE_DATA (&dest_frame, 0);
1039 stride = GST_VIDEO_FRAME_PLANE_STRIDE (&src_frame, 0);
1041 if (format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV &&
1042 dest_format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB) {
1044 gint a, y, u, v, r, g, b;
1046 for (k = 0; k < height; k++) {
1047 for (l = 0; l < width; l++) {
1048 ayuv = GST_READ_UINT32_BE (sdata);
1050 y = (ayuv >> 16) & 0xff;
1051 u = (ayuv >> 8) & 0xff;
1054 r = (298 * y + 459 * v - 63514) >> 8;
1055 g = (298 * y - 55 * u - 136 * v + 19681) >> 8;
1056 b = (298 * y + 541 * u - 73988) >> 8;
1058 r = CLAMP (r, 0, 255);
1059 g = CLAMP (g, 0, 255);
1060 b = CLAMP (b, 0, 255);
1062 /* native endian ARGB */
1063 *(guint32 *) ddata = ((a << 24) | (r << 16) | (g << 8) | b);
1068 sdata += stride - 4 * width;
1070 } else if (format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB &&
1071 dest_format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV) {
1073 gint a, y, u, v, r, g, b;
1075 for (k = 0; k < height; k++) {
1076 for (l = 0; l < width; l++) {
1077 /* native endian ARGB */
1078 argb = *(guint32 *) sdata;
1080 r = (argb >> 16) & 0xff;
1081 g = (argb >> 8) & 0xff;
1084 y = (47 * r + 157 * g + 16 * b + 4096) >> 8;
1085 u = (-26 * r - 87 * g + 112 * b + 32768) >> 8;
1086 v = (112 * r - 102 * g - 10 * b + 32768) >> 8;
1088 y = CLAMP (y, 0, 255);
1089 u = CLAMP (u, 0, 255);
1090 v = CLAMP (v, 0, 255);
1092 GST_WRITE_UINT32_BE (ddata, ((a << 24) | (y << 16) | (u << 8) | v));
1097 sdata += stride - 4 * width;
1100 GST_ERROR ("unsupported conversion");
1101 g_assert_not_reached ();
1104 gst_video_frame_unmap (&src_frame);
1105 gst_video_frame_unmap (&dest_frame);
1109 gst_video_overlay_rectangle_get_pixels_raw_internal (GstVideoOverlayRectangle *
1110 rectangle, GstVideoOverlayFormatFlags flags, gboolean unscaled,
1111 GstVideoFormat wanted_format)
1113 GstVideoOverlayFormatFlags new_flags;
1114 GstVideoOverlayRectangle *scaled_rect = NULL, *conv_rect = NULL;
1116 GstVideoFrame frame;
1119 guint width, height;
1121 guint wanted_height;
1122 gboolean apply_global_alpha;
1123 gboolean revert_global_alpha;
1124 GstVideoFormat format;
1126 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1127 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
1129 width = GST_VIDEO_INFO_WIDTH (&rectangle->info);
1130 height = GST_VIDEO_INFO_HEIGHT (&rectangle->info);
1131 wanted_width = unscaled ? width : rectangle->render_width;
1132 wanted_height = unscaled ? height : rectangle->render_height;
1133 format = GST_VIDEO_INFO_FORMAT (&rectangle->info);
1135 apply_global_alpha =
1136 (! !(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
1137 && !(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA));
1138 revert_global_alpha =
1139 (! !(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
1140 && ! !(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA));
1142 /* This assumes we don't need to adjust the format */
1143 if (wanted_width == width &&
1144 wanted_height == height &&
1145 wanted_format == format &&
1146 gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
1148 /* don't need to apply/revert global-alpha either: */
1149 if ((!apply_global_alpha
1150 || rectangle->applied_global_alpha == rectangle->global_alpha)
1151 && (!revert_global_alpha || rectangle->applied_global_alpha == 1.0)) {
1152 return rectangle->pixels;
1154 /* only apply/revert global-alpha */
1155 scaled_rect = rectangle;
1160 /* see if we've got one cached already */
1161 GST_RECTANGLE_LOCK (rectangle);
1162 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
1163 GstVideoOverlayRectangle *r = l->data;
1165 if (GST_VIDEO_INFO_WIDTH (&r->info) == wanted_width &&
1166 GST_VIDEO_INFO_HEIGHT (&r->info) == wanted_height &&
1167 GST_VIDEO_INFO_FORMAT (&r->info) == wanted_format &&
1168 gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
1169 /* we'll keep these rectangles around until finalize, so it's ok not
1170 * to take our own ref here */
1175 GST_RECTANGLE_UNLOCK (rectangle);
1177 if (scaled_rect != NULL)
1180 /* maybe have one in the right format though */
1181 if (format != wanted_format) {
1182 GST_RECTANGLE_LOCK (rectangle);
1183 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
1184 GstVideoOverlayRectangle *r = l->data;
1186 if (GST_VIDEO_INFO_FORMAT (&r->info) == wanted_format &&
1187 gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
1188 /* we'll keep these rectangles around until finalize, so it's ok not
1189 * to take our own ref here */
1194 GST_RECTANGLE_UNLOCK (rectangle);
1196 conv_rect = rectangle;
1199 if (conv_rect == NULL) {
1200 GstVideoInfo conv_info;
1202 gst_video_overlay_rectangle_convert (&rectangle->info, rectangle->pixels,
1203 wanted_format, &conv_info, &buf);
1204 gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
1205 GST_VIDEO_INFO_FORMAT (&conv_info), width, height);
1206 conv_rect = gst_video_overlay_rectangle_new_raw (buf,
1207 0, 0, width, height, rectangle->flags);
1208 if (rectangle->global_alpha != 1.0)
1209 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1210 rectangle->global_alpha);
1211 gst_buffer_unref (buf);
1212 /* keep this converted one around as well in any case */
1213 GST_RECTANGLE_LOCK (rectangle);
1214 rectangle->scaled_rectangles =
1215 g_list_prepend (rectangle->scaled_rectangles, conv_rect);
1216 GST_RECTANGLE_UNLOCK (rectangle);
1219 /* now we continue from conv_rect */
1220 width = GST_VIDEO_INFO_WIDTH (&conv_rect->info);
1221 height = GST_VIDEO_INFO_HEIGHT (&conv_rect->info);
1222 format = GST_VIDEO_INFO_FORMAT (&conv_rect->info);
1224 /* not cached yet, do the preprocessing and put the result into our cache */
1225 if (wanted_width != width || wanted_height != height) {
1226 GstVideoInfo scaled_info;
1228 /* we could check the cache for a scaled rect with global_alpha == 1 here */
1229 gst_video_blend_scale_linear_RGBA (&conv_rect->info, conv_rect->pixels,
1230 wanted_height, wanted_width, &scaled_info, &buf);
1232 gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
1233 GST_VIDEO_INFO_FORMAT (&conv_rect->info), wanted_width, wanted_height);
1234 } else if (!gst_video_overlay_rectangle_is_same_alpha_type (conv_rect->flags,
1236 /* if we don't have to scale, we have to modify the alpha values, so we
1237 * need to make a copy of the pixel memory (and we take ownership below) */
1238 buf = gst_buffer_copy (conv_rect->pixels);
1239 info = conv_rect->info;
1241 /* do not need to scale or modify alpha values, almost done then */
1242 scaled_rect = conv_rect;
1246 new_flags = conv_rect->flags;
1247 gst_video_frame_map (&frame, &info, buf, GST_MAP_READWRITE);
1248 if (!gst_video_overlay_rectangle_is_same_alpha_type (conv_rect->flags, flags)) {
1249 if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
1250 gst_video_overlay_rectangle_unpremultiply (&frame);
1251 new_flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
1253 gst_video_overlay_rectangle_premultiply (&frame);
1254 new_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
1257 gst_video_frame_unmap (&frame);
1259 scaled_rect = gst_video_overlay_rectangle_new_raw (buf,
1260 0, 0, wanted_width, wanted_height, new_flags);
1261 if (conv_rect->global_alpha != 1.0)
1262 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1263 conv_rect->global_alpha);
1264 gst_buffer_unref (buf);
1266 GST_RECTANGLE_LOCK (rectangle);
1267 rectangle->scaled_rectangles =
1268 g_list_prepend (rectangle->scaled_rectangles, scaled_rect);
1269 GST_RECTANGLE_UNLOCK (rectangle);
1273 GST_RECTANGLE_LOCK (rectangle);
1274 if (apply_global_alpha
1275 && scaled_rect->applied_global_alpha != rectangle->global_alpha) {
1276 gst_video_overlay_rectangle_apply_global_alpha (scaled_rect,
1277 rectangle->global_alpha);
1278 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1279 rectangle->global_alpha);
1280 } else if (revert_global_alpha && scaled_rect->applied_global_alpha != 1.0) {
1281 gst_video_overlay_rectangle_apply_global_alpha (scaled_rect, 1.0);
1283 GST_RECTANGLE_UNLOCK (rectangle);
1285 return scaled_rect->pixels;
1290 * gst_video_overlay_rectangle_get_pixels_raw:
1291 * @rectangle: a #GstVideoOverlayRectangle
1293 * If a global_alpha value != 1 is set for the rectangle, the caller
1294 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1295 * if he wants to apply global-alpha himself. If the flag is not set
1296 * global_alpha is applied internally before returning the pixel-data.
1298 * Returns: (transfer none): a #GstBuffer holding the pixel data with
1299 * format as originally provided and specified in video meta with
1300 * width and height of the render dimensions as per
1301 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1302 * not return a reference, the caller should obtain a reference of her own
1303 * with gst_buffer_ref() if needed.
1306 gst_video_overlay_rectangle_get_pixels_raw (GstVideoOverlayRectangle *
1307 rectangle, GstVideoOverlayFormatFlags flags)
1309 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1310 flags, FALSE, GST_VIDEO_INFO_FORMAT (&rectangle->info));
1314 * gst_video_overlay_rectangle_get_pixels_argb:
1315 * @rectangle: a #GstVideoOverlayRectangle
1317 * If a global_alpha value != 1 is set for the rectangle, the caller
1318 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1319 * if he wants to apply global-alpha himself. If the flag is not set
1320 * global_alpha is applied internally before returning the pixel-data.
1322 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1323 * width and height of the render dimensions as per
1324 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1325 * not return a reference, the caller should obtain a reference of her own
1326 * with gst_buffer_ref() if needed.
1329 gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
1330 rectangle, GstVideoOverlayFormatFlags flags)
1332 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1333 flags, FALSE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB);
1337 * gst_video_overlay_rectangle_get_pixels_ayuv:
1338 * @rectangle: a #GstVideoOverlayRectangle
1340 * If a global_alpha value != 1 is set for the rectangle, the caller
1341 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1342 * if he wants to apply global-alpha himself. If the flag is not set
1343 * global_alpha is applied internally before returning the pixel-data.
1345 * Returns: (transfer none): a #GstBuffer holding the AYUV pixel data with
1346 * width and height of the render dimensions as per
1347 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1348 * not return a reference, the caller should obtain a reference of her own
1349 * with gst_buffer_ref() if needed.
1352 gst_video_overlay_rectangle_get_pixels_ayuv (GstVideoOverlayRectangle *
1353 rectangle, GstVideoOverlayFormatFlags flags)
1355 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1356 flags, FALSE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV);
1360 * gst_video_overlay_rectangle_get_pixels_unscaled_raw:
1361 * @rectangle: a #GstVideoOverlayRectangle
1363 * If a global_alpha value != 1 is set for the rectangle, the caller
1364 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1365 * if he wants to apply global-alpha himself. If the flag is not set
1366 * global_alpha is applied internally before returning the pixel-data.
1368 * Retrieves the pixel data as it is. This is useful if the caller can
1369 * do the scaling itself when handling the overlaying. The rectangle will
1370 * need to be scaled to the render dimensions, which can be retrieved using
1371 * gst_video_overlay_rectangle_get_render_rectangle().
1373 * Returns: (transfer none): a #GstBuffer holding the pixel data with
1374 * #GstVideoMeta set. This function does not return a reference, the caller
1375 * should obtain a reference of her own with gst_buffer_ref() if needed.
1378 gst_video_overlay_rectangle_get_pixels_unscaled_raw (GstVideoOverlayRectangle *
1379 rectangle, GstVideoOverlayFormatFlags flags)
1381 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1383 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1384 flags, TRUE, GST_VIDEO_INFO_FORMAT (&rectangle->info));
1388 * gst_video_overlay_rectangle_get_pixels_unscaled_argb:
1389 * @rectangle: a #GstVideoOverlayRectangle
1391 * If a global_alpha value != 1 is set for the rectangle, the caller
1392 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1393 * if he wants to apply global-alpha himself. If the flag is not set
1394 * global_alpha is applied internally before returning the pixel-data.
1396 * Retrieves the pixel data as it is. This is useful if the caller can
1397 * do the scaling itself when handling the overlaying. The rectangle will
1398 * need to be scaled to the render dimensions, which can be retrieved using
1399 * gst_video_overlay_rectangle_get_render_rectangle().
1401 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1402 * #GstVideoMeta set. This function does not return a reference, the caller
1403 * should obtain a reference of her own with gst_buffer_ref() if needed.
1406 gst_video_overlay_rectangle_get_pixels_unscaled_argb (GstVideoOverlayRectangle *
1407 rectangle, GstVideoOverlayFormatFlags flags)
1409 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1411 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1412 flags, TRUE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB);
1416 * gst_video_overlay_rectangle_get_pixels_unscaled_ayuv:
1417 * @rectangle: a #GstVideoOverlayRectangle
1419 * If a global_alpha value != 1 is set for the rectangle, the caller
1420 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1421 * if he wants to apply global-alpha himself. If the flag is not set
1422 * global_alpha is applied internally before returning the pixel-data.
1424 * Retrieves the pixel data as it is. This is useful if the caller can
1425 * do the scaling itself when handling the overlaying. The rectangle will
1426 * need to be scaled to the render dimensions, which can be retrieved using
1427 * gst_video_overlay_rectangle_get_render_rectangle().
1429 * Returns: (transfer none): a #GstBuffer holding the AYUV pixel data with
1430 * #GstVideoMeta set. This function does not return a reference, the caller
1431 * should obtain a reference of her own with gst_buffer_ref() if needed.
1434 gst_video_overlay_rectangle_get_pixels_unscaled_ayuv (GstVideoOverlayRectangle *
1435 rectangle, GstVideoOverlayFormatFlags flags)
1437 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1439 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1440 flags, TRUE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV);
1444 * gst_video_overlay_rectangle_get_flags:
1445 * @rectangle: a #GstVideoOverlayRectangle
1447 * Retrieves the flags associated with a #GstVideoOverlayRectangle.
1448 * This is useful if the caller can handle both premultiplied alpha and
1449 * non premultiplied alpha, for example. By knowing whether the rectangle
1450 * uses premultiplied or not, it can request the pixel data in the format
1451 * it is stored in, to avoid unnecessary conversion.
1453 * Returns: the #GstVideoOverlayFormatFlags associated with the rectangle.
1455 GstVideoOverlayFormatFlags
1456 gst_video_overlay_rectangle_get_flags (GstVideoOverlayRectangle * rectangle)
1458 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle),
1459 GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1461 return rectangle->flags;
1465 * gst_video_overlay_rectangle_get_global_alpha:
1466 * @rectangle: a #GstVideoOverlayRectangle
1468 * Retrieves the global-alpha value associated with a #GstVideoOverlayRectangle.
1470 * Returns: the global-alpha value associated with the rectangle.
1473 gst_video_overlay_rectangle_get_global_alpha (GstVideoOverlayRectangle *
1476 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), -1);
1478 return rectangle->global_alpha;
1482 * gst_video_overlay_rectangle_set_global_alpha:
1483 * @rectangle: a #GstVideoOverlayRectangle
1485 * Sets the global alpha value associated with a #GstVideoOverlayRectangle. Per-
1486 * pixel alpha values are multiplied with this value. Valid
1487 * values: 0 <= global_alpha <= 1; 1 to deactivate.
1489 # @rectangle must be writable, meaning its refcount must be 1. You can
1490 * make the rectangles inside a #GstVideoOverlayComposition writable using
1491 * gst_video_overlay_composition_make_writable() or
1492 * gst_video_overlay_composition_copy().
1495 gst_video_overlay_rectangle_set_global_alpha (GstVideoOverlayRectangle *
1496 rectangle, gfloat global_alpha)
1498 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
1499 g_return_if_fail (global_alpha >= 0 && global_alpha <= 1);
1501 if (rectangle->global_alpha != global_alpha) {
1502 rectangle->global_alpha = global_alpha;
1503 if (global_alpha != 1)
1504 rectangle->flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
1506 rectangle->flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
1507 /* update seq_num automatically to signal the consumer, that data has changed
1508 * note, that this might mislead renderers, that can handle global-alpha
1509 * themselves, because what they want to know is whether the actual pixel data
1511 rectangle->seq_num = gst_video_overlay_get_seqnum ();
1516 * gst_video_overlay_rectangle_copy:
1517 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to copy
1519 * Makes a copy of @rectangle, so that it is possible to modify it
1520 * (e.g. to change the render co-ordinates or render dimension). The
1521 * actual overlay pixel data buffers contained in the rectangle are not
1524 * Returns: (transfer full): a new #GstVideoOverlayRectangle equivalent
1527 GstVideoOverlayRectangle *
1528 gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
1530 GstVideoOverlayRectangle *copy;
1532 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1534 copy = gst_video_overlay_rectangle_new_raw (rectangle->pixels,
1535 rectangle->x, rectangle->y,
1536 rectangle->render_width, rectangle->render_height, rectangle->flags);
1537 if (rectangle->global_alpha != 1)
1538 gst_video_overlay_rectangle_set_global_alpha (copy,
1539 rectangle->global_alpha);
1545 * gst_video_overlay_rectangle_get_seqnum:
1546 * @rectangle: a #GstVideoOverlayRectangle
1548 * Returns the sequence number of this rectangle. Sequence numbers are
1549 * monotonically increasing and unique for overlay compositions and rectangles
1550 * (meaning there will never be a rectangle with the same sequence number as
1553 * Using the sequence number of a rectangle as an indicator for changed
1554 * pixel-data of a rectangle is dangereous. Some API calls, like e.g.
1555 * gst_video_overlay_rectangle_set_global_alpha(), automatically update
1556 * the per rectangle sequence number, which is misleading for renderers/
1557 * consumers, that handle global-alpha themselves. For them the
1558 * pixel-data returned by gst_video_overlay_rectangle_get_pixels_*()
1559 * wont be different for different global-alpha values. In this case a
1560 * renderer could also use the GstBuffer pointers as a hint for changed
1563 * Returns: the sequence number of @rectangle
1566 gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)
1568 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), 0);
1570 return rectangle->seq_num;