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 * @title: GstVideoOverlayRectangle
25 * @short_description: Video Buffer Overlay Compositions (Subtitles, Logos)
27 * Functions to create and handle overlay compositions on video buffers.
29 * An overlay composition describes one or more overlay rectangles to be
30 * blended on top of a video buffer.
32 * This API serves two main purposes:
34 * * it can be used to attach overlay information (subtitles or logos)
35 * to non-raw video buffers such as GL/VAAPI/VDPAU surfaces. The actual
36 * blending of the overlay can then be done by e.g. the video sink that
37 * processes these non-raw buffers.
39 * * it can also be used to blend overlay rectangles on top of raw video
40 * buffers, thus consolidating blending functionality for raw video in
43 * Together, this allows existing overlay elements to easily handle raw
44 * and non-raw video as input in without major changes (once the overlays
45 * have been put into a #GstVideoOverlayComposition object anyway) - for raw
46 * video the overlay can just use the blending function to blend the data
47 * on top of the video, and for surface buffers it can just attach them to
48 * the buffer and let the sink render the overlays.
53 * - provide accessors for seq_num and other fields (as needed)
54 * - allow overlay to set/get original pango markup string on/from rectangle
61 #include "video-overlay-composition.h"
62 #include "video-blend.h"
63 #include "gstvideometa.h"
66 struct _GstVideoOverlayComposition
71 GstVideoOverlayRectangle **rectangles;
73 /* lowest rectangle sequence number still used by the upstream
74 * overlay element. This way a renderer maintaining some kind of
75 * rectangles <-> surface cache can know when to free cached
76 * surfaces/rectangles. */
77 guint min_seq_num_used;
79 /* sequence number for the composition (same series as rectangles) */
83 struct _GstVideoOverlayRectangle
87 /* Position on video frame and dimension of output rectangle in
88 * output frame terms (already adjusted for the PAR of the output
89 * frame). x/y can be negative (overlay will be clipped then) */
91 guint render_width, render_height;
93 /* Info on overlay pixels (format, width, height) */
96 /* The flags associated to this rectangle */
97 GstVideoOverlayFormatFlags flags;
99 /* Refcounted blob of memory, no caps or timestamps */
102 /* FIXME: how to express source like text or pango markup?
103 * (just add source type enum + source buffer with data)
105 * FOR 0.10: always send pixel blobs, but attach source data in
106 * addition (reason: if downstream changes, we can't renegotiate
107 * that properly, if we just do a query of supported formats from
108 * the start). Sink will just ignore pixels and use pango markup
109 * from source data if it supports that.
111 * FOR 0.11: overlay should query formats (pango markup, pixels)
112 * supported by downstream and then only send that. We can
113 * renegotiate via the reconfigure event.
116 /* sequence number: useful for backends/renderers/sinks that want
117 * to maintain a cache of rectangles <-> surfaces. The value of
118 * the min_seq_num_used in the composition tells the renderer which
119 * rectangles have expired. */
122 /* global alpha: global alpha value of the rectangle. Each each per-pixel
123 * alpha value of image-data will be multiplied with the global alpha value
125 * Can be used for efficient fading in/out of overlay rectangles.
126 * GstElements that render OverlayCompositions and don't support global alpha
127 * should simply ignore it.*/
130 /* track alpha-values already applied: */
131 gfloat applied_global_alpha;
132 /* store initial per-pixel alpha values: */
133 guint8 *initial_alpha;
135 /* FIXME: we may also need a (private) way to cache converted/scaled
139 GList *scaled_rectangles;
142 #define GST_RECTANGLE_LOCK(rect) g_mutex_lock(&rect->lock)
143 #define GST_RECTANGLE_UNLOCK(rect) g_mutex_unlock(&rect->lock)
145 /* --------------------------- utility functions --------------------------- */
147 #ifndef GST_DISABLE_GST_DEBUG
149 #define GST_CAT_DEFAULT ensure_debug_category()
151 static GstDebugCategory *
152 ensure_debug_category (void)
154 static gsize cat_gonce = 0;
156 if (g_once_init_enter (&cat_gonce)) {
159 cat_done = (gsize) _gst_debug_category_new ("video-composition", 0,
160 "video overlay composition");
162 g_once_init_leave (&cat_gonce, cat_done);
165 return (GstDebugCategory *) cat_gonce;
170 #define ensure_debug_category() /* NOOP */
172 #endif /* GST_DISABLE_GST_DEBUG */
175 gst_video_overlay_get_seqnum (void)
177 static gint seqnum; /* 0 */
179 return (guint) g_atomic_int_add (&seqnum, 1);
183 gst_video_overlay_composition_meta_init (GstMeta * meta, gpointer params,
186 GstVideoOverlayCompositionMeta *ometa;
188 ometa = (GstVideoOverlayCompositionMeta *) meta;
190 ometa->overlay = NULL;
196 gst_video_overlay_composition_meta_free (GstMeta * meta, GstBuffer * buf)
198 GstVideoOverlayCompositionMeta *ometa;
200 ometa = (GstVideoOverlayCompositionMeta *) meta;
203 gst_video_overlay_composition_unref (ometa->overlay);
207 gst_video_overlay_composition_meta_transform (GstBuffer * dest, GstMeta * meta,
208 GstBuffer * buffer, GQuark type, gpointer data)
210 GstVideoOverlayCompositionMeta *dmeta, *smeta;
212 smeta = (GstVideoOverlayCompositionMeta *) meta;
214 if (GST_META_TRANSFORM_IS_COPY (type)) {
215 GstMetaTransformCopy *copy = data;
218 GST_DEBUG ("copy video overlay composition metadata");
220 /* only copy if the complete data is copied as well */
222 (GstVideoOverlayCompositionMeta *) gst_buffer_add_meta (dest,
223 GST_VIDEO_OVERLAY_COMPOSITION_META_INFO, NULL);
227 dmeta->overlay = gst_video_overlay_composition_ref (smeta->overlay);
230 /* return FALSE, if transform type is not supported */
237 gst_video_overlay_composition_meta_api_get_type (void)
239 static GType type = 0;
240 static const gchar *tags[] = { NULL };
242 if (g_once_init_enter (&type)) {
244 gst_meta_api_type_register ("GstVideoOverlayCompositionMetaAPI", tags);
245 g_once_init_leave (&type, _type);
250 /* video overlay composition metadata */
252 gst_video_overlay_composition_meta_get_info (void)
254 static const GstMetaInfo *video_overlay_composition_meta_info = NULL;
256 if (g_once_init_enter ((GstMetaInfo **) &
257 video_overlay_composition_meta_info)) {
258 const GstMetaInfo *meta =
259 gst_meta_register (GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE,
260 "GstVideoOverlayCompositionMeta",
261 sizeof (GstVideoOverlayCompositionMeta),
262 (GstMetaInitFunction) gst_video_overlay_composition_meta_init,
263 (GstMetaFreeFunction) gst_video_overlay_composition_meta_free,
264 (GstMetaTransformFunction)
265 gst_video_overlay_composition_meta_transform);
266 g_once_init_leave ((GstMetaInfo **) & video_overlay_composition_meta_info,
267 (GstMetaInfo *) meta);
269 return video_overlay_composition_meta_info;
273 * gst_buffer_add_video_overlay_composition_meta:
275 * @comp: (allow-none): a #GstVideoOverlayComposition
277 * Sets an overlay composition on a buffer. The buffer will obtain its own
278 * reference to the composition, meaning this function does not take ownership
281 * Returns: (transfer none): a #GstVideoOverlayCompositionMeta
283 GstVideoOverlayCompositionMeta *
284 gst_buffer_add_video_overlay_composition_meta (GstBuffer * buf,
285 GstVideoOverlayComposition * comp)
287 GstVideoOverlayCompositionMeta *ometa;
289 g_return_val_if_fail (gst_buffer_is_writable (buf), NULL);
291 ometa = (GstVideoOverlayCompositionMeta *)
292 gst_buffer_add_meta (buf, GST_VIDEO_OVERLAY_COMPOSITION_META_INFO, NULL);
294 ometa->overlay = gst_video_overlay_composition_ref (comp);
299 /* ------------------------------ composition ------------------------------ */
301 #define RECTANGLE_ARRAY_STEP 4 /* premature optimization */
303 GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayComposition,
304 gst_video_overlay_composition);
307 gst_video_overlay_composition_free (GstMiniObject * mini_obj)
309 GstVideoOverlayComposition *comp = (GstVideoOverlayComposition *) mini_obj;
312 num = comp->num_rectangles;
315 gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (comp->rectangles[num -
316 1]), GST_MINI_OBJECT_CAST (comp));
317 gst_video_overlay_rectangle_unref (comp->rectangles[num - 1]);
321 g_free (comp->rectangles);
322 comp->rectangles = NULL;
323 comp->num_rectangles = 0;
325 g_slice_free (GstVideoOverlayComposition, comp);
329 * gst_video_overlay_composition_new:
330 * @rectangle: (transfer none) (nullable): a #GstVideoOverlayRectangle to add to the
333 * Creates a new video overlay composition object to hold one or more
334 * overlay rectangles.
336 * Note that since 1.20 this allows to pass %NULL for @rectangle.
338 * Returns: (transfer full): a new #GstVideoOverlayComposition. Unref with
339 * gst_video_overlay_composition_unref() when no longer needed.
341 GstVideoOverlayComposition *
342 gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
344 GstVideoOverlayComposition *comp;
346 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle)
349 comp = g_slice_new0 (GstVideoOverlayComposition);
351 gst_mini_object_init (GST_MINI_OBJECT_CAST (comp), 0,
352 GST_TYPE_VIDEO_OVERLAY_COMPOSITION,
353 (GstMiniObjectCopyFunction) gst_video_overlay_composition_copy,
354 NULL, (GstMiniObjectFreeFunction) gst_video_overlay_composition_free);
356 comp->rectangles = g_new0 (GstVideoOverlayRectangle *, RECTANGLE_ARRAY_STEP);
358 comp->seq_num = gst_video_overlay_get_seqnum ();
360 /* since the rectangle was created earlier, its seqnum is smaller than ours */
361 comp->min_seq_num_used = rectangle->seq_num;
363 GST_LOG ("new composition %p: seq_num %u", comp, comp->seq_num);
366 gst_video_overlay_composition_add_rectangle (comp, rectangle);
372 * gst_video_overlay_composition_add_rectangle:
373 * @comp: a #GstVideoOverlayComposition
374 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
377 * Adds an overlay rectangle to an existing overlay composition object. This
378 * must be done right after creating the overlay composition.
381 gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
382 GstVideoOverlayRectangle * rectangle)
384 g_return_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp));
385 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
386 g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (comp)));
388 if (comp->num_rectangles % RECTANGLE_ARRAY_STEP == 0) {
390 g_renew (GstVideoOverlayRectangle *, comp->rectangles,
391 comp->num_rectangles + RECTANGLE_ARRAY_STEP);
394 comp->rectangles[comp->num_rectangles] =
395 gst_video_overlay_rectangle_ref (rectangle);
396 gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (rectangle),
397 GST_MINI_OBJECT_CAST (comp));
398 comp->num_rectangles += 1;
400 comp->min_seq_num_used = MIN (comp->min_seq_num_used, rectangle->seq_num);
402 GST_LOG ("composition %p: added rectangle %p", comp, rectangle);
406 * gst_video_overlay_composition_n_rectangles:
407 * @comp: a #GstVideoOverlayComposition
409 * Returns the number of #GstVideoOverlayRectangle<!-- -->s contained in @comp.
411 * Returns: the number of rectangles
414 gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
416 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
418 return comp->num_rectangles;
422 * gst_video_overlay_composition_get_rectangle:
423 * @comp: a #GstVideoOverlayComposition
424 * @n: number of the rectangle to get
426 * Returns the @n-th #GstVideoOverlayRectangle contained in @comp.
428 * Returns: (transfer none): the @n-th rectangle, or NULL if @n is out of
429 * bounds. Will not return a new reference, the caller will need to
430 * obtain her own reference using gst_video_overlay_rectangle_ref()
433 GstVideoOverlayRectangle *
434 gst_video_overlay_composition_get_rectangle (GstVideoOverlayComposition * comp,
437 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
439 if (n >= comp->num_rectangles)
442 return comp->rectangles[n];
446 gst_video_overlay_rectangle_needs_scaling (GstVideoOverlayRectangle * r)
448 return (GST_VIDEO_INFO_WIDTH (&r->info) != r->render_width ||
449 GST_VIDEO_INFO_HEIGHT (&r->info) != r->render_height);
453 * gst_video_overlay_composition_blend:
454 * @comp: a #GstVideoOverlayComposition
455 * @video_buf: a #GstVideoFrame containing raw video data in a
456 * supported format. It should be mapped using GST_MAP_READWRITE
458 * Blends the overlay rectangles in @comp on top of the raw video data
459 * contained in @video_buf. The data in @video_buf must be writable and
460 * mapped appropriately.
462 * Since @video_buf data is read and will be modified, it ought be
463 * mapped with flag GST_MAP_READWRITE.
465 /* FIXME: formats with more than 8 bit per component which get unpacked into
466 * ARGB64 or AYUV64 (such as v210, v216, UYVP, GRAY16_LE and GRAY16_BE)
467 * are not supported yet by the code in video-blend.c.
470 gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
471 GstVideoFrame * video_buf)
473 GstVideoInfo scaled_info;
475 GstVideoFrame rectangle_frame;
477 GstBuffer *pixels = NULL;
482 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), FALSE);
483 g_return_val_if_fail (video_buf != NULL, FALSE);
485 w = GST_VIDEO_FRAME_WIDTH (video_buf);
486 h = GST_VIDEO_FRAME_HEIGHT (video_buf);
487 fmt = GST_VIDEO_FRAME_FORMAT (video_buf);
489 num = comp->num_rectangles;
490 GST_LOG ("Blending composition %p with %u rectangles onto video buffer %p "
491 "(%ux%u, format %u)", comp, num, video_buf, w, h, fmt);
493 for (n = 0; n < num; ++n) {
494 GstVideoOverlayRectangle *rect;
495 gboolean needs_scaling;
497 rect = comp->rectangles[n];
499 GST_LOG (" rectangle %u %p: %ux%u, format %u", n, rect,
500 GST_VIDEO_INFO_WIDTH (&rect->info), GST_VIDEO_INFO_HEIGHT (&rect->info),
501 GST_VIDEO_INFO_FORMAT (&rect->info));
503 needs_scaling = gst_video_overlay_rectangle_needs_scaling (rect);
505 gst_video_blend_scale_linear_RGBA (&rect->info, rect->pixels,
506 rect->render_height, rect->render_width, &scaled_info, &pixels);
507 vinfo = &scaled_info;
509 pixels = gst_buffer_ref (rect->pixels);
513 gst_video_frame_map (&rectangle_frame, vinfo, pixels, GST_MAP_READ);
515 ret = gst_video_blend (video_buf, &rectangle_frame, rect->x, rect->y,
517 gst_video_frame_unmap (&rectangle_frame);
519 GST_WARNING ("Could not blend overlay rectangle onto video buffer");
522 /* FIXME: should cache scaled pixels in the rectangle struct */
523 gst_buffer_unref (pixels);
530 * gst_video_overlay_composition_copy:
531 * @comp: (transfer none): a #GstVideoOverlayComposition to copy
533 * Makes a copy of @comp and all contained rectangles, so that it is possible
534 * to modify the composition and contained rectangles (e.g. add additional
535 * rectangles or change the render co-ordinates or render dimension). The
536 * actual overlay pixel data buffers contained in the rectangles are not
539 * Returns: (transfer full): a new #GstVideoOverlayComposition equivalent
542 GstVideoOverlayComposition *
543 gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
545 GstVideoOverlayComposition *copy;
546 GstVideoOverlayRectangle *rect;
549 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
551 if (G_LIKELY (comp->num_rectangles == 0))
552 return gst_video_overlay_composition_new (NULL);
554 rect = gst_video_overlay_rectangle_copy (comp->rectangles[0]);
555 copy = gst_video_overlay_composition_new (rect);
556 gst_video_overlay_rectangle_unref (rect);
558 for (n = 1; n < comp->num_rectangles; ++n) {
559 rect = gst_video_overlay_rectangle_copy (comp->rectangles[n]);
560 gst_video_overlay_composition_add_rectangle (copy, rect);
561 gst_video_overlay_rectangle_unref (rect);
568 * gst_video_overlay_composition_make_writable:
569 * @comp: (transfer full): a #GstVideoOverlayComposition to copy
571 * Takes ownership of @comp and returns a version of @comp that is writable
572 * (i.e. can be modified). Will either return @comp right away, or create a
573 * new writable copy of @comp and unref @comp itself. All the contained
574 * rectangles will also be copied, but the actual overlay pixel data buffers
575 * contained in the rectangles are not copied.
577 * Returns: (transfer full): a writable #GstVideoOverlayComposition
578 * equivalent to @comp.
580 GstVideoOverlayComposition *
581 gst_video_overlay_composition_make_writable (GstVideoOverlayComposition * comp)
583 GstVideoOverlayComposition *writable_comp;
585 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
587 if (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (comp))) {
590 for (n = 0; n < comp->num_rectangles; ++n) {
591 if (!gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (comp->rectangles
600 writable_comp = gst_video_overlay_composition_copy (comp);
601 gst_video_overlay_composition_unref (comp);
603 return writable_comp;
607 * gst_video_overlay_composition_get_seqnum:
608 * @comp: a #GstVideoOverlayComposition
610 * Returns the sequence number of this composition. Sequence numbers are
611 * monotonically increasing and unique for overlay compositions and rectangles
612 * (meaning there will never be a rectangle with the same sequence number as
615 * Returns: the sequence number of @comp
618 gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
620 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
622 return comp->seq_num;
625 /* ------------------------------ rectangles ------------------------------ -*/
627 GST_DEFINE_MINI_OBJECT_TYPE (GstVideoOverlayRectangle,
628 gst_video_overlay_rectangle);
631 gst_video_overlay_rectangle_free (GstMiniObject * mini_obj)
633 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
635 gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (rect->pixels),
636 GST_MINI_OBJECT_CAST (rect));
637 gst_buffer_replace (&rect->pixels, NULL);
639 while (rect->scaled_rectangles != NULL) {
640 GstVideoOverlayRectangle *scaled_rect = rect->scaled_rectangles->data;
642 gst_video_overlay_rectangle_unref (scaled_rect);
644 rect->scaled_rectangles =
645 g_list_delete_link (rect->scaled_rectangles, rect->scaled_rectangles);
648 g_free (rect->initial_alpha);
649 g_mutex_clear (&rect->lock);
651 g_slice_free (GstVideoOverlayRectangle, rect);
654 static inline gboolean
655 gst_video_overlay_rectangle_check_flags (GstVideoOverlayFormatFlags flags)
657 /* Check flags only contains flags we know about */
658 return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA |
659 GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)) == 0;
663 gst_video_overlay_rectangle_is_same_alpha_type (GstVideoOverlayFormatFlags
664 flags1, GstVideoOverlayFormatFlags flags2)
666 return ((flags1 ^ flags2) & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
672 * gst_video_overlay_rectangle_new_raw:
673 * @pixels: (transfer none): a #GstBuffer pointing to the pixel memory
674 * @render_x: the X co-ordinate on the video where the top-left corner of this
675 * overlay rectangle should be rendered to
676 * @render_y: the Y co-ordinate on the video where the top-left corner of this
677 * overlay rectangle should be rendered to
678 * @render_width: the render width of this rectangle on the video
679 * @render_height: the render height of this rectangle on the video
682 * Creates a new video overlay rectangle with ARGB or AYUV pixel data.
683 * The layout in case of ARGB of the components in memory is B-G-R-A
684 * on little-endian platforms
685 * (corresponding to #GST_VIDEO_FORMAT_BGRA) and A-R-G-B on big-endian
686 * platforms (corresponding to #GST_VIDEO_FORMAT_ARGB). In other words,
687 * pixels are treated as 32-bit words and the lowest 8 bits then contain
688 * the blue component value and the highest 8 bits contain the alpha
689 * component value. Unless specified in the flags, the RGB values are
690 * non-premultiplied. This is the format that is used by most hardware,
691 * and also many rendering libraries such as Cairo, for example.
692 * The pixel data buffer must have #GstVideoMeta set.
694 * Returns: (transfer full): a new #GstVideoOverlayRectangle. Unref with
695 * gst_video_overlay_rectangle_unref() when no longer needed.
697 GstVideoOverlayRectangle *
698 gst_video_overlay_rectangle_new_raw (GstBuffer * pixels,
699 gint render_x, gint render_y, guint render_width, guint render_height,
700 GstVideoOverlayFormatFlags flags)
702 GstVideoOverlayRectangle *rect;
704 GstVideoFormat format;
707 g_return_val_if_fail (GST_IS_BUFFER (pixels), NULL);
708 g_return_val_if_fail (render_height > 0 && render_width > 0, NULL);
709 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
711 /* buffer must have video meta with some expected settings */
712 vmeta = gst_buffer_get_video_meta (pixels);
713 g_return_val_if_fail (vmeta, NULL);
714 g_return_val_if_fail (vmeta->format ==
715 GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB ||
716 vmeta->format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV, NULL);
717 g_return_val_if_fail (vmeta->flags == GST_VIDEO_FRAME_FLAG_NONE, NULL);
719 format = vmeta->format;
720 width = vmeta->width;
721 height = vmeta->height;
723 /* technically ((height-1)*stride)+width might be okay too */
724 g_return_val_if_fail (gst_buffer_get_size (pixels) >= height * width * 4,
726 g_return_val_if_fail (height > 0 && width > 0, NULL);
728 rect = g_slice_new0 (GstVideoOverlayRectangle);
730 gst_mini_object_init (GST_MINI_OBJECT_CAST (rect), 0,
731 GST_TYPE_VIDEO_OVERLAY_RECTANGLE,
732 (GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy,
733 NULL, (GstMiniObjectFreeFunction) gst_video_overlay_rectangle_free);
735 g_mutex_init (&rect->lock);
737 rect->pixels = gst_buffer_ref (pixels);
738 gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (pixels),
739 GST_MINI_OBJECT_CAST (rect));
740 rect->scaled_rectangles = NULL;
742 gst_video_info_init (&rect->info);
743 if (!gst_video_info_set_format (&rect->info, format, width, height)) {
744 gst_mini_object_unref (GST_MINI_OBJECT_CAST (rect));
747 if (flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
748 rect->info.flags |= GST_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
752 rect->render_width = render_width;
753 rect->render_height = render_height;
755 rect->global_alpha = 1.0;
756 rect->applied_global_alpha = 1.0;
757 rect->initial_alpha = NULL;
761 rect->seq_num = gst_video_overlay_get_seqnum ();
763 GST_LOG ("new rectangle %p: %ux%u => %ux%u @ %u,%u, seq_num %u, format %u, "
764 "flags %x, pixels %p, global_alpha=%f", rect, width, height, render_width,
765 render_height, render_x, render_y, rect->seq_num, format,
766 rect->flags, pixels, rect->global_alpha);
772 * gst_video_overlay_rectangle_get_render_rectangle:
773 * @rectangle: a #GstVideoOverlayRectangle
774 * @render_x: (out) (allow-none): address where to store the X render offset
775 * @render_y: (out) (allow-none): address where to store the Y render offset
776 * @render_width: (out) (allow-none): address where to store the render width
777 * @render_height: (out) (allow-none): address where to store the render height
779 * Retrieves the render position and render dimension of the overlay
780 * rectangle on the video.
782 * Returns: TRUE if valid render dimensions were retrieved.
785 gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
786 rectangle, gint * render_x, gint * render_y, guint * render_width,
787 guint * render_height)
789 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), FALSE);
792 *render_x = rectangle->x;
794 *render_y = rectangle->y;
796 *render_width = rectangle->render_width;
798 *render_height = rectangle->render_height;
804 * gst_video_overlay_rectangle_set_render_rectangle:
805 * @rectangle: a #GstVideoOverlayRectangle
806 * @render_x: render X position of rectangle on video
807 * @render_y: render Y position of rectangle on video
808 * @render_width: render width of rectangle
809 * @render_height: render height of rectangle
811 * Sets the render position and dimensions of the rectangle on the video.
812 * This function is mainly for elements that modify the size of the video
813 * in some way (e.g. through scaling or cropping) and need to adjust the
814 * details of any overlays to match the operation that changed the size.
816 * @rectangle must be writable, meaning its refcount must be 1. You can
817 * make the rectangles inside a #GstVideoOverlayComposition writable using
818 * gst_video_overlay_composition_make_writable() or
819 * gst_video_overlay_composition_copy().
822 gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
823 rectangle, gint render_x, gint render_y, guint render_width,
826 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
827 g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST
830 rectangle->x = render_x;
831 rectangle->y = render_y;
832 rectangle->render_width = render_width;
833 rectangle->render_height = render_height;
838 gst_video_overlay_rectangle_premultiply_0 (GstVideoFrame * frame)
841 int width = GST_VIDEO_FRAME_WIDTH (frame);
842 int height = GST_VIDEO_FRAME_HEIGHT (frame);
843 int stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
844 guint8 *data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
846 for (j = 0; j < height; ++j) {
851 for (i = 0; i < width; ++i) {
853 line[1] = line[1] * a / 255;
854 line[2] = line[2] * a / 255;
855 line[3] = line[3] * a / 255;
862 gst_video_overlay_rectangle_premultiply_3 (GstVideoFrame * frame)
865 int width = GST_VIDEO_FRAME_WIDTH (frame);
866 int height = GST_VIDEO_FRAME_HEIGHT (frame);
867 int stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
868 guint8 *data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
870 for (j = 0; j < height; ++j) {
875 for (i = 0; i < width; ++i) {
877 line[0] = line[0] * a / 255;
878 line[1] = line[1] * a / 255;
879 line[2] = line[2] * a / 255;
886 gst_video_overlay_rectangle_premultiply (GstVideoFrame * frame)
890 alpha_offset = GST_VIDEO_FRAME_COMP_POFFSET (frame, 3);
891 switch (alpha_offset) {
893 gst_video_overlay_rectangle_premultiply_0 (frame);
896 gst_video_overlay_rectangle_premultiply_3 (frame);
899 g_assert_not_reached ();
906 gst_video_overlay_rectangle_unpremultiply_0 (GstVideoFrame * frame)
909 int width = GST_VIDEO_FRAME_WIDTH (frame);
910 int height = GST_VIDEO_FRAME_HEIGHT (frame);
911 int stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
912 guint8 *data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
914 for (j = 0; j < height; ++j) {
919 for (i = 0; i < width; ++i) {
922 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
923 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
924 line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
932 gst_video_overlay_rectangle_unpremultiply_3 (GstVideoFrame * frame)
935 int width = GST_VIDEO_FRAME_WIDTH (frame);
936 int height = GST_VIDEO_FRAME_HEIGHT (frame);
937 int stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
938 guint8 *data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
940 for (j = 0; j < height; ++j) {
945 for (i = 0; i < width; ++i) {
948 line[0] = MIN ((line[0] * 255 + a / 2) / a, 255);
949 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
950 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
958 gst_video_overlay_rectangle_unpremultiply (GstVideoFrame * frame)
962 alpha_offset = GST_VIDEO_FRAME_COMP_POFFSET (frame, 3);
963 switch (alpha_offset) {
965 gst_video_overlay_rectangle_unpremultiply_0 (frame);
968 gst_video_overlay_rectangle_unpremultiply_3 (frame);
971 g_assert_not_reached ();
978 gst_video_overlay_rectangle_extract_alpha (GstVideoOverlayRectangle * rect)
982 gint i, j, w, h, stride, alpha_offset;
984 alpha_offset = GST_VIDEO_INFO_COMP_POFFSET (&rect->info, 3);
985 g_return_if_fail (alpha_offset == 0 || alpha_offset == 3);
987 gst_video_frame_map (&frame, &rect->info, rect->pixels, GST_MAP_READ);
988 src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
989 w = GST_VIDEO_INFO_WIDTH (&rect->info);
990 h = GST_VIDEO_INFO_HEIGHT (&rect->info);
991 stride = GST_VIDEO_INFO_PLANE_STRIDE (&rect->info, 0);
993 g_free (rect->initial_alpha);
994 rect->initial_alpha = g_malloc (w * h);
995 dst = rect->initial_alpha;
997 for (i = 0; i < h; i++) {
998 for (j = 0; j < w; j++) {
999 *dst = src[alpha_offset];
1003 src += stride - 4 * w;
1005 gst_video_frame_unmap (&frame);
1010 gst_video_overlay_rectangle_apply_global_alpha (GstVideoOverlayRectangle * rect,
1014 GstVideoFrame frame;
1015 gint i, j, w, h, stride;
1016 gint argb_a, argb_r, argb_g, argb_b;
1019 g_assert (!(rect->applied_global_alpha != 1.0
1020 && rect->initial_alpha == NULL));
1022 alpha_offset = GST_VIDEO_INFO_COMP_POFFSET (&rect->info, 3);
1023 g_return_if_fail (alpha_offset == 0 || alpha_offset == 3);
1025 if (global_alpha == rect->applied_global_alpha)
1028 if (rect->initial_alpha == NULL)
1029 gst_video_overlay_rectangle_extract_alpha (rect);
1031 src = rect->initial_alpha;
1032 if (!gst_buffer_is_writable (rect->pixels)) {
1033 gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (rect->pixels),
1034 GST_MINI_OBJECT_CAST (rect));
1035 rect->pixels = gst_buffer_copy (rect->pixels);
1036 gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (rect->pixels),
1037 GST_MINI_OBJECT_CAST (rect));
1040 gst_video_frame_map (&frame, &rect->info, rect->pixels, GST_MAP_READ);
1041 dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
1042 w = GST_VIDEO_INFO_WIDTH (&rect->info);
1043 h = GST_VIDEO_INFO_HEIGHT (&rect->info);
1044 stride = GST_VIDEO_INFO_PLANE_STRIDE (&rect->info, 0);
1046 argb_a = GST_VIDEO_INFO_COMP_POFFSET (&rect->info, 3);
1047 argb_r = (argb_a + 1) % 4;
1048 argb_g = (argb_a + 2) % 4;
1049 argb_b = (argb_a + 3) % 4;
1051 for (i = 0; i < h; i++) {
1052 for (j = 0; j < w; j++) {
1053 guint8 na = (guint8) (*src * global_alpha);
1055 if (! !(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) {
1057 (guint8) ((double) (dst[argb_r] * 255) / (double) dst[argb_a]) *
1060 (guint8) ((double) (dst[argb_g] * 255) / (double) dst[argb_a]) *
1063 (guint8) ((double) (dst[argb_b] * 255) / (double) dst[argb_a]) *
1070 dst += stride - 4 * w;
1072 gst_video_frame_unmap (&frame);
1074 rect->applied_global_alpha = global_alpha;
1078 gst_video_overlay_rectangle_convert (const GstVideoInfo * src,
1079 GstBuffer * src_buffer, GstVideoFormat dest_format, GstVideoInfo * dest,
1080 GstBuffer ** dest_buffer)
1082 gint width, height, stride;
1083 GstVideoFrame src_frame, dest_frame;
1084 GstVideoFormat format;
1086 guint8 *sdata, *ddata;
1088 format = GST_VIDEO_INFO_FORMAT (src);
1090 width = GST_VIDEO_INFO_WIDTH (src);
1091 height = GST_VIDEO_INFO_HEIGHT (src);
1093 gst_video_info_init (dest);
1094 if (!gst_video_info_set_format (dest, dest_format, width, height)) {
1095 g_warn_if_reached ();
1099 *dest_buffer = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (dest));
1101 gst_video_frame_map (&src_frame, src, src_buffer, GST_MAP_READ);
1102 gst_video_frame_map (&dest_frame, dest, *dest_buffer, GST_MAP_WRITE);
1104 sdata = GST_VIDEO_FRAME_PLANE_DATA (&src_frame, 0);
1105 ddata = GST_VIDEO_FRAME_PLANE_DATA (&dest_frame, 0);
1106 stride = GST_VIDEO_FRAME_PLANE_STRIDE (&src_frame, 0);
1108 if (format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV &&
1109 dest_format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB) {
1111 gint a, y, u, v, r, g, b;
1113 for (k = 0; k < height; k++) {
1114 for (l = 0; l < width; l++) {
1115 ayuv = GST_READ_UINT32_BE (sdata);
1117 y = (ayuv >> 16) & 0xff;
1118 u = (ayuv >> 8) & 0xff;
1121 r = (298 * y + 459 * v - 63514) >> 8;
1122 g = (298 * y - 55 * u - 136 * v + 19681) >> 8;
1123 b = (298 * y + 541 * u - 73988) >> 8;
1125 r = CLAMP (r, 0, 255);
1126 g = CLAMP (g, 0, 255);
1127 b = CLAMP (b, 0, 255);
1129 /* native endian ARGB */
1130 *(guint32 *) ddata = ((a << 24) | (r << 16) | (g << 8) | b);
1135 sdata += stride - 4 * width;
1137 } else if (format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB &&
1138 dest_format == GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV) {
1140 gint a, y, u, v, r, g, b;
1142 for (k = 0; k < height; k++) {
1143 for (l = 0; l < width; l++) {
1144 /* native endian ARGB */
1145 argb = *(guint32 *) sdata;
1147 r = (argb >> 16) & 0xff;
1148 g = (argb >> 8) & 0xff;
1151 y = (47 * r + 157 * g + 16 * b + 4096) >> 8;
1152 u = (-26 * r - 87 * g + 112 * b + 32768) >> 8;
1153 v = (112 * r - 102 * g - 10 * b + 32768) >> 8;
1155 y = CLAMP (y, 0, 255);
1156 u = CLAMP (u, 0, 255);
1157 v = CLAMP (v, 0, 255);
1159 GST_WRITE_UINT32_BE (ddata, ((a << 24) | (y << 16) | (u << 8) | v));
1164 sdata += stride - 4 * width;
1167 GST_ERROR ("unsupported conversion");
1168 g_assert_not_reached ();
1171 gst_video_frame_unmap (&src_frame);
1172 gst_video_frame_unmap (&dest_frame);
1176 gst_video_overlay_rectangle_get_pixels_raw_internal (GstVideoOverlayRectangle *
1177 rectangle, GstVideoOverlayFormatFlags flags, gboolean unscaled,
1178 GstVideoFormat wanted_format)
1180 GstVideoOverlayFormatFlags new_flags;
1181 GstVideoOverlayRectangle *scaled_rect = NULL, *conv_rect = NULL;
1183 GstVideoFrame frame;
1186 guint width, height;
1188 guint wanted_height;
1189 gboolean apply_global_alpha;
1190 gboolean revert_global_alpha;
1191 GstVideoFormat format;
1193 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1194 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
1196 width = GST_VIDEO_INFO_WIDTH (&rectangle->info);
1197 height = GST_VIDEO_INFO_HEIGHT (&rectangle->info);
1198 wanted_width = unscaled ? width : rectangle->render_width;
1199 wanted_height = unscaled ? height : rectangle->render_height;
1200 format = GST_VIDEO_INFO_FORMAT (&rectangle->info);
1202 apply_global_alpha =
1203 (! !(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
1204 && !(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA));
1205 revert_global_alpha =
1206 (! !(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
1207 && ! !(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA));
1209 /* This assumes we don't need to adjust the format */
1210 if (wanted_width == width &&
1211 wanted_height == height &&
1212 wanted_format == format &&
1213 gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
1215 /* don't need to apply/revert global-alpha either: */
1216 if ((!apply_global_alpha
1217 || rectangle->applied_global_alpha == rectangle->global_alpha)
1218 && (!revert_global_alpha || rectangle->applied_global_alpha == 1.0)) {
1219 return rectangle->pixels;
1221 /* only apply/revert global-alpha */
1222 scaled_rect = rectangle;
1227 /* see if we've got one cached already */
1228 GST_RECTANGLE_LOCK (rectangle);
1229 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
1230 GstVideoOverlayRectangle *r = l->data;
1232 if (GST_VIDEO_INFO_WIDTH (&r->info) == wanted_width &&
1233 GST_VIDEO_INFO_HEIGHT (&r->info) == wanted_height &&
1234 GST_VIDEO_INFO_FORMAT (&r->info) == wanted_format &&
1235 gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
1236 /* we'll keep these rectangles around until finalize, so it's ok not
1237 * to take our own ref here */
1242 GST_RECTANGLE_UNLOCK (rectangle);
1244 if (scaled_rect != NULL)
1247 /* maybe have one in the right format though */
1248 if (format != wanted_format) {
1249 GST_RECTANGLE_LOCK (rectangle);
1250 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
1251 GstVideoOverlayRectangle *r = l->data;
1253 if (GST_VIDEO_INFO_FORMAT (&r->info) == wanted_format &&
1254 gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
1255 /* we'll keep these rectangles around until finalize, so it's ok not
1256 * to take our own ref here */
1261 GST_RECTANGLE_UNLOCK (rectangle);
1263 conv_rect = rectangle;
1266 if (conv_rect == NULL) {
1267 GstVideoInfo conv_info;
1269 gst_video_overlay_rectangle_convert (&rectangle->info, rectangle->pixels,
1270 wanted_format, &conv_info, &buf);
1271 gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
1272 GST_VIDEO_INFO_FORMAT (&conv_info), width, height);
1273 conv_rect = gst_video_overlay_rectangle_new_raw (buf,
1274 0, 0, width, height, rectangle->flags);
1275 if (rectangle->global_alpha != 1.0)
1276 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1277 rectangle->global_alpha);
1278 gst_buffer_unref (buf);
1279 /* keep this converted one around as well in any case */
1280 GST_RECTANGLE_LOCK (rectangle);
1281 rectangle->scaled_rectangles =
1282 g_list_prepend (rectangle->scaled_rectangles, conv_rect);
1283 GST_RECTANGLE_UNLOCK (rectangle);
1286 /* now we continue from conv_rect */
1287 width = GST_VIDEO_INFO_WIDTH (&conv_rect->info);
1288 height = GST_VIDEO_INFO_HEIGHT (&conv_rect->info);
1289 format = GST_VIDEO_INFO_FORMAT (&conv_rect->info);
1291 /* not cached yet, do the preprocessing and put the result into our cache */
1292 if (wanted_width != width || wanted_height != height) {
1293 GstVideoInfo scaled_info;
1295 /* we could check the cache for a scaled rect with global_alpha == 1 here */
1296 gst_video_blend_scale_linear_RGBA (&conv_rect->info, conv_rect->pixels,
1297 wanted_height, wanted_width, &scaled_info, &buf);
1299 gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
1300 GST_VIDEO_INFO_FORMAT (&conv_rect->info), wanted_width, wanted_height);
1301 } else if (!gst_video_overlay_rectangle_is_same_alpha_type (conv_rect->flags,
1303 /* if we don't have to scale, we have to modify the alpha values, so we
1304 * need to make a copy of the pixel memory (and we take ownership below) */
1305 buf = gst_buffer_copy (conv_rect->pixels);
1306 info = conv_rect->info;
1308 /* do not need to scale or modify alpha values, almost done then */
1309 scaled_rect = conv_rect;
1313 new_flags = conv_rect->flags;
1314 gst_video_frame_map (&frame, &info, buf, GST_MAP_READWRITE);
1315 if (!gst_video_overlay_rectangle_is_same_alpha_type (conv_rect->flags, flags)) {
1316 if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
1317 gst_video_overlay_rectangle_unpremultiply (&frame);
1318 new_flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
1320 gst_video_overlay_rectangle_premultiply (&frame);
1321 new_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
1324 gst_video_frame_unmap (&frame);
1326 scaled_rect = gst_video_overlay_rectangle_new_raw (buf,
1327 0, 0, wanted_width, wanted_height, new_flags);
1328 if (conv_rect->global_alpha != 1.0)
1329 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1330 conv_rect->global_alpha);
1331 gst_buffer_unref (buf);
1333 GST_RECTANGLE_LOCK (rectangle);
1334 rectangle->scaled_rectangles =
1335 g_list_prepend (rectangle->scaled_rectangles, scaled_rect);
1336 GST_RECTANGLE_UNLOCK (rectangle);
1340 GST_RECTANGLE_LOCK (rectangle);
1341 if (apply_global_alpha
1342 && scaled_rect->applied_global_alpha != rectangle->global_alpha) {
1343 gst_video_overlay_rectangle_apply_global_alpha (scaled_rect,
1344 rectangle->global_alpha);
1345 gst_video_overlay_rectangle_set_global_alpha (scaled_rect,
1346 rectangle->global_alpha);
1347 } else if (revert_global_alpha && scaled_rect->applied_global_alpha != 1.0) {
1348 gst_video_overlay_rectangle_apply_global_alpha (scaled_rect, 1.0);
1350 GST_RECTANGLE_UNLOCK (rectangle);
1352 return scaled_rect->pixels;
1357 * gst_video_overlay_rectangle_get_pixels_raw:
1358 * @rectangle: a #GstVideoOverlayRectangle
1360 * If a global_alpha value != 1 is set for the rectangle, the caller
1361 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1362 * if he wants to apply global-alpha himself. If the flag is not set
1363 * global_alpha is applied internally before returning the pixel-data.
1365 * Returns: (transfer none): a #GstBuffer holding the pixel data with
1366 * format as originally provided and specified in video meta with
1367 * width and height of the render dimensions as per
1368 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1369 * not return a reference, the caller should obtain a reference of her own
1370 * with gst_buffer_ref() if needed.
1373 gst_video_overlay_rectangle_get_pixels_raw (GstVideoOverlayRectangle *
1374 rectangle, GstVideoOverlayFormatFlags flags)
1376 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1377 flags, FALSE, GST_VIDEO_INFO_FORMAT (&rectangle->info));
1381 * gst_video_overlay_rectangle_get_pixels_argb:
1382 * @rectangle: a #GstVideoOverlayRectangle
1384 * If a global_alpha value != 1 is set for the rectangle, the caller
1385 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1386 * if he wants to apply global-alpha himself. If the flag is not set
1387 * global_alpha is applied internally before returning the pixel-data.
1389 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1390 * width and height of the render dimensions as per
1391 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1392 * not return a reference, the caller should obtain a reference of her own
1393 * with gst_buffer_ref() if needed.
1396 gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
1397 rectangle, GstVideoOverlayFormatFlags flags)
1399 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1400 flags, FALSE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB);
1404 * gst_video_overlay_rectangle_get_pixels_ayuv:
1405 * @rectangle: a #GstVideoOverlayRectangle
1407 * If a global_alpha value != 1 is set for the rectangle, the caller
1408 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1409 * if he wants to apply global-alpha himself. If the flag is not set
1410 * global_alpha is applied internally before returning the pixel-data.
1412 * Returns: (transfer none): a #GstBuffer holding the AYUV pixel data with
1413 * width and height of the render dimensions as per
1414 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1415 * not return a reference, the caller should obtain a reference of her own
1416 * with gst_buffer_ref() if needed.
1419 gst_video_overlay_rectangle_get_pixels_ayuv (GstVideoOverlayRectangle *
1420 rectangle, GstVideoOverlayFormatFlags flags)
1422 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1423 flags, FALSE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV);
1427 * gst_video_overlay_rectangle_get_pixels_unscaled_raw:
1428 * @rectangle: a #GstVideoOverlayRectangle
1430 * If a global_alpha value != 1 is set for the rectangle, the caller
1431 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1432 * if he wants to apply global-alpha himself. If the flag is not set
1433 * global_alpha is applied internally before returning the pixel-data.
1435 * Retrieves the pixel data as it is. This is useful if the caller can
1436 * do the scaling itself when handling the overlaying. The rectangle will
1437 * need to be scaled to the render dimensions, which can be retrieved using
1438 * gst_video_overlay_rectangle_get_render_rectangle().
1440 * Returns: (transfer none): a #GstBuffer holding the pixel data with
1441 * #GstVideoMeta set. This function does not return a reference, the caller
1442 * should obtain a reference of her own with gst_buffer_ref() if needed.
1445 gst_video_overlay_rectangle_get_pixels_unscaled_raw (GstVideoOverlayRectangle *
1446 rectangle, GstVideoOverlayFormatFlags flags)
1448 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1450 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1451 flags, TRUE, GST_VIDEO_INFO_FORMAT (&rectangle->info));
1455 * gst_video_overlay_rectangle_get_pixels_unscaled_argb:
1456 * @rectangle: a #GstVideoOverlayRectangle
1458 * If a global_alpha value != 1 is set for the rectangle, the caller
1459 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1460 * if he wants to apply global-alpha himself. If the flag is not set
1461 * global_alpha is applied internally before returning the pixel-data.
1463 * Retrieves the pixel data as it is. This is useful if the caller can
1464 * do the scaling itself when handling the overlaying. The rectangle will
1465 * need to be scaled to the render dimensions, which can be retrieved using
1466 * gst_video_overlay_rectangle_get_render_rectangle().
1468 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1469 * #GstVideoMeta set. This function does not return a reference, the caller
1470 * should obtain a reference of her own with gst_buffer_ref() if needed.
1473 gst_video_overlay_rectangle_get_pixels_unscaled_argb (GstVideoOverlayRectangle *
1474 rectangle, GstVideoOverlayFormatFlags flags)
1476 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1478 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1479 flags, TRUE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB);
1483 * gst_video_overlay_rectangle_get_pixels_unscaled_ayuv:
1484 * @rectangle: a #GstVideoOverlayRectangle
1486 * If a global_alpha value != 1 is set for the rectangle, the caller
1487 * should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
1488 * if he wants to apply global-alpha himself. If the flag is not set
1489 * global_alpha is applied internally before returning the pixel-data.
1491 * Retrieves the pixel data as it is. This is useful if the caller can
1492 * do the scaling itself when handling the overlaying. The rectangle will
1493 * need to be scaled to the render dimensions, which can be retrieved using
1494 * gst_video_overlay_rectangle_get_render_rectangle().
1496 * Returns: (transfer none): a #GstBuffer holding the AYUV pixel data with
1497 * #GstVideoMeta set. This function does not return a reference, the caller
1498 * should obtain a reference of her own with gst_buffer_ref() if needed.
1501 gst_video_overlay_rectangle_get_pixels_unscaled_ayuv (GstVideoOverlayRectangle *
1502 rectangle, GstVideoOverlayFormatFlags flags)
1504 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1506 return gst_video_overlay_rectangle_get_pixels_raw_internal (rectangle,
1507 flags, TRUE, GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_YUV);
1511 * gst_video_overlay_rectangle_get_flags:
1512 * @rectangle: a #GstVideoOverlayRectangle
1514 * Retrieves the flags associated with a #GstVideoOverlayRectangle.
1515 * This is useful if the caller can handle both premultiplied alpha and
1516 * non premultiplied alpha, for example. By knowing whether the rectangle
1517 * uses premultiplied or not, it can request the pixel data in the format
1518 * it is stored in, to avoid unnecessary conversion.
1520 * Returns: the #GstVideoOverlayFormatFlags associated with the rectangle.
1522 GstVideoOverlayFormatFlags
1523 gst_video_overlay_rectangle_get_flags (GstVideoOverlayRectangle * rectangle)
1525 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle),
1526 GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1528 return rectangle->flags;
1532 * gst_video_overlay_rectangle_get_global_alpha:
1533 * @rectangle: a #GstVideoOverlayRectangle
1535 * Retrieves the global-alpha value associated with a #GstVideoOverlayRectangle.
1537 * Returns: the global-alpha value associated with the rectangle.
1540 gst_video_overlay_rectangle_get_global_alpha (GstVideoOverlayRectangle *
1543 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), -1);
1545 return rectangle->global_alpha;
1549 * gst_video_overlay_rectangle_set_global_alpha:
1550 * @rectangle: a #GstVideoOverlayRectangle
1551 * @global_alpha: Global alpha value (0 to 1.0)
1553 * Sets the global alpha value associated with a #GstVideoOverlayRectangle. Per-
1554 * pixel alpha values are multiplied with this value. Valid
1555 * values: 0 <= global_alpha <= 1; 1 to deactivate.
1557 * @rectangle must be writable, meaning its refcount must be 1. You can
1558 * make the rectangles inside a #GstVideoOverlayComposition writable using
1559 * gst_video_overlay_composition_make_writable() or
1560 * gst_video_overlay_composition_copy().
1563 gst_video_overlay_rectangle_set_global_alpha (GstVideoOverlayRectangle *
1564 rectangle, gfloat global_alpha)
1566 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
1567 g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST
1569 g_return_if_fail (global_alpha >= 0 && global_alpha <= 1);
1571 if (rectangle->global_alpha != global_alpha) {
1572 rectangle->global_alpha = global_alpha;
1573 if (global_alpha != 1)
1574 rectangle->flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
1576 rectangle->flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
1577 /* update seq_num automatically to signal the consumer, that data has changed
1578 * note, that this might mislead renderers, that can handle global-alpha
1579 * themselves, because what they want to know is whether the actual pixel data
1581 rectangle->seq_num = gst_video_overlay_get_seqnum ();
1586 * gst_video_overlay_rectangle_copy:
1587 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to copy
1589 * Makes a copy of @rectangle, so that it is possible to modify it
1590 * (e.g. to change the render co-ordinates or render dimension). The
1591 * actual overlay pixel data buffers contained in the rectangle are not
1594 * Returns: (transfer full): a new #GstVideoOverlayRectangle equivalent
1597 GstVideoOverlayRectangle *
1598 gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
1600 GstVideoOverlayRectangle *copy;
1602 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1604 copy = gst_video_overlay_rectangle_new_raw (rectangle->pixels,
1605 rectangle->x, rectangle->y,
1606 rectangle->render_width, rectangle->render_height, rectangle->flags);
1607 if (rectangle->global_alpha != 1)
1608 gst_video_overlay_rectangle_set_global_alpha (copy,
1609 rectangle->global_alpha);
1615 * gst_video_overlay_rectangle_get_seqnum:
1616 * @rectangle: a #GstVideoOverlayRectangle
1618 * Returns the sequence number of this rectangle. Sequence numbers are
1619 * monotonically increasing and unique for overlay compositions and rectangles
1620 * (meaning there will never be a rectangle with the same sequence number as
1623 * Using the sequence number of a rectangle as an indicator for changed
1624 * pixel-data of a rectangle is dangereous. Some API calls, like e.g.
1625 * gst_video_overlay_rectangle_set_global_alpha(), automatically update
1626 * the per rectangle sequence number, which is misleading for renderers/
1627 * consumers, that handle global-alpha themselves. For them the
1628 * pixel-data returned by gst_video_overlay_rectangle_get_pixels_*()
1629 * won't be different for different global-alpha values. In this case a
1630 * renderer could also use the GstBuffer pointers as a hint for changed
1633 * Returns: the sequence number of @rectangle
1636 gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)
1638 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), 0);
1640 return rectangle->seq_num;