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., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, 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.
62 * - provide accessors for seq_num and other fields (as needed)
63 * - allow overlay to set/get original pango markup string on/from rectangle
70 #include "video-overlay-composition.h"
71 #include "video-blend.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 _GstVideoOverlayCompositionClass
92 GstMiniObjectClass parent_class;
95 struct _GstVideoOverlayRectangle
99 /* Position on video frame and dimension of output rectangle in
100 * output frame terms (already adjusted for the PAR of the output
101 * frame). x/y can be negative (overlay will be clipped then) */
103 guint render_width, render_height;
105 /* Dimensions of overlay pixels */
106 guint width, height, stride;
108 /* The format of the data in pixels */
109 GstVideoFormat format;
111 /* The flags associated to this rectangle */
112 GstVideoOverlayFormatFlags flags;
114 /* Refcounted blob of memory, no caps or timestamps */
117 /* FIXME: how to express source like text or pango markup?
118 * (just add source type enum + source buffer with data)
120 * FOR 0.10: always send pixel blobs, but attach source data in
121 * addition (reason: if downstream changes, we can't renegotiate
122 * that properly, if we just do a query of supported formats from
123 * the start). Sink will just ignore pixels and use pango markup
124 * from source data if it supports that.
126 * FOR 0.11: overlay should query formats (pango markup, pixels)
127 * supported by downstream and then only send that. We can
128 * renegotiate via the reconfigure event.
131 /* sequence number: useful for backends/renderers/sinks that want
132 * to maintain a cache of rectangles <-> surfaces. The value of
133 * the min_seq_num_used in the composition tells the renderer which
134 * rectangles have expired. */
137 /* FIXME: we may also need a (private) way to cache converted/scaled
139 #if !GLIB_CHECK_VERSION (2, 31, 0)
145 GList *scaled_rectangles;
148 struct _GstVideoOverlayRectangleClass
150 GstMiniObjectClass parent_class;
153 #if !GLIB_CHECK_VERSION (2, 31, 0)
154 #define GST_RECTANGLE_LOCK(rect) g_static_mutex_lock(&rect->lock)
155 #define GST_RECTANGLE_UNLOCK(rect) g_static_mutex_unlock(&rect->lock)
157 #define GST_RECTANGLE_LOCK(rect) g_mutex_lock(&rect->lock)
158 #define GST_RECTANGLE_UNLOCK(rect) g_mutex_unlock(&rect->lock)
161 static void gst_video_overlay_composition_class_init (GstMiniObjectClass * k);
162 static void gst_video_overlay_composition_finalize (GstMiniObject * comp);
163 static void gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass);
164 static void gst_video_overlay_rectangle_finalize (GstMiniObject * rect);
166 /* --------------------------- utility functions --------------------------- */
168 #ifndef GST_DISABLE_GST_DEBUG
170 #define GST_CAT_DEFAULT ensure_debug_category()
172 static GstDebugCategory *
173 ensure_debug_category (void)
175 static gsize cat_gonce = 0;
177 if (g_once_init_enter (&cat_gonce)) {
180 cat_done = (gsize) _gst_debug_category_new ("video-composition", 0,
181 "video overlay composition");
183 g_once_init_leave (&cat_gonce, cat_done);
186 return (GstDebugCategory *) cat_gonce;
191 #define ensure_debug_category() /* NOOP */
193 #endif /* GST_DISABLE_GST_DEBUG */
196 gst_video_overlay_get_seqnum (void)
198 static gint seqnum; /* 0 */
200 #if GLIB_CHECK_VERSION(2,29,5)
201 return (guint) g_atomic_int_add (&seqnum, 1);
203 return (guint) g_atomic_int_exchange_and_add (&seqnum, 1);
207 #define GST_OVERLAY_COMPOSITION_QUARK gst_overlay_composition_quark_get()
209 gst_overlay_composition_quark_get (void)
211 static gsize quark_gonce = 0;
213 if (g_once_init_enter (&quark_gonce)) {
216 quark = (gsize) g_quark_from_static_string ("GstVideoOverlayComposition");
218 g_once_init_leave (&quark_gonce, quark);
221 return (GQuark) quark_gonce;
224 #define COMPOSITION_QUARK composition_quark_get()
226 composition_quark_get (void)
228 static gsize quark_gonce = 0;
230 if (g_once_init_enter (&quark_gonce)) {
233 quark = (gsize) g_quark_from_static_string ("composition");
235 g_once_init_leave (&quark_gonce, quark);
238 return (GQuark) quark_gonce;
242 * gst_video_buffer_set_overlay_composition:
244 * @comp: (allow-none): a #GstVideoOverlayComposition, or NULL to clear a
245 * previously-set composition
247 * Sets an overlay composition on a buffer. The buffer will obtain its own
248 * reference to the composition, meaning this function does not take ownership
254 gst_video_buffer_set_overlay_composition (GstBuffer * buf,
255 GstVideoOverlayComposition * comp)
257 gst_buffer_set_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK,
258 gst_structure_id_new (GST_OVERLAY_COMPOSITION_QUARK,
259 COMPOSITION_QUARK, GST_TYPE_VIDEO_OVERLAY_COMPOSITION, comp, NULL));
263 * gst_video_buffer_get_overlay_composition:
266 * Get the overlay composition that has previously been attached to a buffer
267 * with gst_video_buffer_get_overlay_composition(), usually by another element
270 * Returns: (transfer none): the #GstVideoOverlayComposition attached to
271 * this buffer, or NULL. Does not return a reference to the composition,
272 * caller must obtain her own ref via gst_video_overlay_composition_ref()
277 GstVideoOverlayComposition *
278 gst_video_buffer_get_overlay_composition (GstBuffer * buf)
280 const GstStructure *s;
283 s = gst_buffer_get_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK);
287 val = gst_structure_id_get_value (s, COMPOSITION_QUARK);
291 return GST_VIDEO_OVERLAY_COMPOSITION (gst_value_get_mini_object (val));
294 /* ------------------------------ composition ------------------------------ */
296 #define RECTANGLE_ARRAY_STEP 4 /* premature optimization */
299 gst_video_overlay_composition_get_type (void)
301 static volatile gsize type_id = 0;
303 if (g_once_init_enter (&type_id)) {
304 GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
305 g_intern_static_string ("GstVideoOverlayComposition"),
306 sizeof (GstVideoOverlayCompositionClass),
307 (GClassInitFunc) gst_video_overlay_composition_class_init,
308 sizeof (GstVideoOverlayComposition),
312 g_once_init_leave (&type_id, new_type_id);
319 gst_video_overlay_composition_finalize (GstMiniObject * mini_obj)
321 GstVideoOverlayComposition *comp = (GstVideoOverlayComposition *) mini_obj;
324 num = comp->num_rectangles;
327 gst_video_overlay_rectangle_unref (comp->rectangles[num - 1]);
331 g_free (comp->rectangles);
332 comp->rectangles = NULL;
333 comp->num_rectangles = 0;
335 /* not chaining up to GstMiniObject's finalize for now, we know it's empty */
339 gst_video_overlay_composition_class_init (GstMiniObjectClass * klass)
341 klass->finalize = gst_video_overlay_composition_finalize;
342 klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_composition_copy;
346 * gst_video_overlay_composition_new:
347 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
350 * Creates a new video overlay composition object to hold one or more
351 * overlay rectangles.
353 * Returns: (transfer full): a new #GstVideoOverlayComposition. Unref with
354 * gst_video_overlay_composition_unref() when no longer needed.
358 GstVideoOverlayComposition *
359 gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
361 GstVideoOverlayComposition *comp;
364 /* FIXME: should we allow empty compositions? Could also be expressed as
365 * buffer without a composition on it. Maybe there are cases where doing
366 * an empty new + _add() in a loop is easier? */
367 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
369 comp = (GstVideoOverlayComposition *)
370 gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_COMPOSITION);
372 comp->rectangles = g_new0 (GstVideoOverlayRectangle *, RECTANGLE_ARRAY_STEP);
373 comp->rectangles[0] = gst_video_overlay_rectangle_ref (rectangle);
374 comp->num_rectangles = 1;
376 comp->seq_num = gst_video_overlay_get_seqnum ();
378 /* since the rectangle was created earlier, its seqnum is smaller than ours */
379 comp->min_seq_num_used = rectangle->seq_num;
381 GST_LOG ("new composition %p: seq_num %u with rectangle %p", comp,
382 comp->seq_num, rectangle);
388 * gst_video_overlay_composition_add_rectangle:
389 * @comp: a #GstVideoOverlayComposition
390 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
393 * Adds an overlay rectangle to an existing overlay composition object. This
394 * must be done right after creating the overlay composition.
399 gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
400 GstVideoOverlayRectangle * rectangle)
402 g_return_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp));
403 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
404 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1);
406 if (comp->num_rectangles % RECTANGLE_ARRAY_STEP == 0) {
408 g_renew (GstVideoOverlayRectangle *, comp->rectangles,
409 comp->num_rectangles + RECTANGLE_ARRAY_STEP);
412 comp->rectangles[comp->num_rectangles] =
413 gst_video_overlay_rectangle_ref (rectangle);
414 comp->num_rectangles += 1;
416 comp->min_seq_num_used = MIN (comp->min_seq_num_used, rectangle->seq_num);
418 GST_LOG ("composition %p: added rectangle %p", comp, rectangle);
422 * gst_video_overlay_composition_n_rectangles:
423 * @comp: a #GstVideoOverlayComposition
425 * Returns the number of #GstVideoOverlayRectangle<!-- -->s contained in @comp.
427 * Returns: the number of rectangles
432 gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
434 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
436 return comp->num_rectangles;
440 * gst_video_overlay_composition_get_rectangle:
441 * @comp: a #GstVideoOverlayComposition
442 * @n: number of the rectangle to get
444 * Returns the @n-th #GstVideoOverlayRectangle contained in @comp.
446 * Returns: (transfer none): the @n-th rectangle, or NULL if @n is out of
447 * bounds. Will not return a new reference, the caller will need to
448 * obtain her own reference using gst_video_overlay_rectangle_ref()
453 GstVideoOverlayRectangle *
454 gst_video_overlay_composition_get_rectangle (GstVideoOverlayComposition * comp,
457 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
459 if (n >= comp->num_rectangles)
462 return comp->rectangles[n];
466 gst_video_overlay_rectangle_needs_scaling (GstVideoOverlayRectangle * r)
468 return (r->width != r->render_width || r->height != r->render_height);
472 * gst_video_overlay_composition_blend:
473 * @comp: a #GstVideoOverlayComposition
474 * @video_buf: a #GstBuffer containing raw video data in a supported format
476 * Blends the overlay rectangles in @comp on top of the raw video data
477 * contained in @video_buf. The data in @video_buf must be writable. If
478 * needed, use gst_buffer_make_writable() before calling this function to
479 * ensure a buffer is writable. @video_buf must also have valid raw video
485 gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
486 GstBuffer * video_buf)
488 GstBlendVideoFormatInfo video_info, rectangle_info;
494 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), FALSE);
495 g_return_val_if_fail (GST_IS_BUFFER (video_buf), FALSE);
496 g_return_val_if_fail (gst_buffer_is_writable (video_buf), FALSE);
497 g_return_val_if_fail (GST_BUFFER_CAPS (video_buf) != NULL, FALSE);
499 if (!gst_video_format_parse_caps (GST_BUFFER_CAPS (video_buf), &fmt, &w, &h)) {
500 gchar *str = gst_caps_to_string (GST_BUFFER_CAPS (video_buf));
501 g_warning ("%s: could not parse video buffer caps '%s'", GST_FUNCTION, str);
506 video_blend_format_info_init (&video_info, GST_BUFFER_DATA (video_buf),
509 num = comp->num_rectangles;
510 GST_LOG ("Blending composition %p with %u rectangles onto video buffer %p "
511 "(%ux%u, format %u)", comp, num, video_buf, w, h, fmt);
513 for (n = 0; n < num; ++n) {
514 GstVideoOverlayRectangle *rect;
515 gboolean needs_scaling;
517 rect = comp->rectangles[n];
519 GST_LOG (" rectangle %u %p: %ux%u, format %u", n, rect, rect->height,
520 rect->width, rect->format);
522 video_blend_format_info_init (&rectangle_info,
523 GST_BUFFER_DATA (rect->pixels), rect->height, rect->width,
525 !!(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
527 needs_scaling = gst_video_overlay_rectangle_needs_scaling (rect);
529 video_blend_scale_linear_RGBA (&rectangle_info, rect->render_height,
533 ret = video_blend (&video_info, &rectangle_info, rect->x, rect->y);
535 GST_WARNING ("Could not blend overlay rectangle onto video buffer");
538 /* FIXME: should cache scaled pixels in the rectangle struct */
540 g_free (rectangle_info.pixels);
547 * gst_video_overlay_composition_copy:
548 * @comp: (transfer none): a #GstVideoOverlayComposition to copy
550 * Makes a copy of @comp and all contained rectangles, so that it is possible
551 * to modify the composition and contained rectangles (e.g. add additional
552 * rectangles or change the render co-ordinates or render dimension). The
553 * actual overlay pixel data buffers contained in the rectangles are not
556 * Returns: (transfer full): a new #GstVideoOverlayComposition equivalent
561 GstVideoOverlayComposition *
562 gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
564 GstVideoOverlayComposition *copy;
565 GstVideoOverlayRectangle *rect;
568 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
570 if (G_LIKELY (comp->num_rectangles == 0))
571 return gst_video_overlay_composition_new (NULL);
573 rect = gst_video_overlay_rectangle_copy (comp->rectangles[0]);
574 copy = gst_video_overlay_composition_new (rect);
575 gst_video_overlay_rectangle_unref (rect);
577 for (n = 1; n < comp->num_rectangles; ++n) {
578 rect = gst_video_overlay_rectangle_copy (comp->rectangles[n]);
579 gst_video_overlay_composition_add_rectangle (copy, rect);
580 gst_video_overlay_rectangle_unref (rect);
587 * gst_video_overlay_composition_make_writable:
588 * @comp: (transfer full): a #GstVideoOverlayComposition to copy
590 * Takes ownership of @comp and returns a version of @comp that is writable
591 * (i.e. can be modified). Will either return @comp right away, or create a
592 * new writable copy of @comp and unref @comp itself. All the contained
593 * rectangles will also be copied, but the actual overlay pixel data buffers
594 * contained in the rectangles are not copied.
596 * Returns: (transfer full): a writable #GstVideoOverlayComposition
597 * equivalent to @comp.
601 GstVideoOverlayComposition *
602 gst_video_overlay_composition_make_writable (GstVideoOverlayComposition * comp)
604 GstVideoOverlayComposition *writable_comp;
606 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
608 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1) {
611 for (n = 0; n < comp->num_rectangles; ++n) {
612 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp->rectangles[n]) != 1)
620 writable_comp = gst_video_overlay_composition_copy (comp);
621 gst_video_overlay_composition_unref (comp);
623 return writable_comp;
627 * gst_video_overlay_composition_get_seqnum:
628 * @comp: a #GstVideoOverlayComposition
630 * Returns the sequence number of this composition. Sequence numbers are
631 * monotonically increasing and unique for overlay compositions and rectangles
632 * (meaning there will never be a rectangle with the same sequence number as
635 * Returns: the sequence number of @comp
640 gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
642 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
644 return comp->seq_num;
647 /* ------------------------------ rectangles ------------------------------ -*/
649 static void gst_video_overlay_rectangle_instance_init (GstMiniObject * miniobj);
652 gst_video_overlay_rectangle_get_type (void)
654 static volatile gsize type_id = 0;
656 if (g_once_init_enter (&type_id)) {
657 GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
658 g_intern_static_string ("GstVideoOverlayRectangle"),
659 sizeof (GstVideoOverlayRectangleClass),
660 (GClassInitFunc) gst_video_overlay_rectangle_class_init,
661 sizeof (GstVideoOverlayRectangle),
662 (GInstanceInitFunc) gst_video_overlay_rectangle_instance_init,
665 g_once_init_leave (&type_id, new_type_id);
672 gst_video_overlay_rectangle_finalize (GstMiniObject * mini_obj)
674 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
676 gst_buffer_replace (&rect->pixels, NULL);
678 while (rect->scaled_rectangles != NULL) {
679 GstVideoOverlayRectangle *scaled_rect = rect->scaled_rectangles->data;
681 gst_video_overlay_rectangle_unref (scaled_rect);
683 rect->scaled_rectangles =
684 g_list_delete_link (rect->scaled_rectangles, rect->scaled_rectangles);
686 #if !GLIB_CHECK_VERSION (2, 31, 0)
687 g_static_mutex_free (&rect->lock);
689 g_mutex_clear (&rect->lock);
691 /* not chaining up to GstMiniObject's finalize for now, we know it's empty */
695 gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass)
697 klass->finalize = gst_video_overlay_rectangle_finalize;
698 klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy;
702 gst_video_overlay_rectangle_instance_init (GstMiniObject * mini_obj)
704 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
706 #if !GLIB_CHECK_VERSION (2, 31, 0)
707 g_static_mutex_init (&rect->lock);
709 g_mutex_init (&rect->lock);
713 static inline gboolean
714 gst_video_overlay_rectangle_check_flags (GstVideoOverlayFormatFlags flags)
716 /* Check flags only contains flags we know about */
717 return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) == 0;
721 gst_video_overlay_rectangle_is_same_alpha_type (GstVideoOverlayFormatFlags
722 flags1, GstVideoOverlayFormatFlags flags2)
724 return ((flags1 ^ flags2) & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
730 * gst_video_overlay_rectangle_new_argb:
731 * @pixels: (transfer none): a #GstBuffer pointing to the pixel memory
732 * @width: the width of the rectangle in @pixels
733 * @height: the height of the rectangle in @pixels
734 * @stride: the stride of the rectangle in @pixels in bytes (>= 4*width)
735 * @x: the X co-ordinate on the video where the top-left corner of this
736 * overlay rectangle should be rendered to
737 * @y: the Y co-ordinate on the video where the top-left corner of this
738 * overlay rectangle should be rendered to
739 * @render_width: the render width of this rectangle on the video
740 * @render_height: the render height of this rectangle on the video
743 * Creates a new video overlay rectangle with ARGB pixel data. The layout
744 * of the components in memory is B-G-R-A on little-endian platforms
745 * (corresponding to #GST_VIDEO_FORMAT_BGRA) and A-R-G-B on big-endian
746 * platforms (corresponding to #GST_VIDEO_FORMAT_ARGB). In other words,
747 * pixels are treated as 32-bit words and the lowest 8 bits then contain
748 * the blue component value and the highest 8 bits contain the alpha
749 * component value. Unless specified in the flags, the RGB values are
750 * non-premultiplied. This is the format that is used by most hardware,
751 * and also many rendering libraries such as Cairo, for example.
753 * Returns: (transfer full): a new #GstVideoOverlayRectangle. Unref with
754 * gst_video_overlay_rectangle_unref() when no longer needed.
758 GstVideoOverlayRectangle *
759 gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
760 guint width, guint height, guint stride, gint render_x, gint render_y,
761 guint render_width, guint render_height, GstVideoOverlayFormatFlags flags)
763 GstVideoOverlayRectangle *rect;
765 g_return_val_if_fail (GST_IS_BUFFER (pixels), NULL);
766 /* technically ((height-1)*stride)+width might be okay too */
767 g_return_val_if_fail (GST_BUFFER_SIZE (pixels) >= height * stride, NULL);
768 g_return_val_if_fail (stride >= (4 * width), NULL);
769 g_return_val_if_fail (height > 0 && width > 0, NULL);
770 g_return_val_if_fail (render_height > 0 && render_width > 0, NULL);
771 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
773 rect = (GstVideoOverlayRectangle *)
774 gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_RECTANGLE);
776 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
777 rect->format = GST_VIDEO_FORMAT_BGRA;
779 rect->format = GST_VIDEO_FORMAT_ARGB;
782 rect->pixels = gst_buffer_ref (pixels);
785 rect->height = height;
786 rect->stride = stride;
790 rect->render_width = render_width;
791 rect->render_height = render_height;
795 rect->seq_num = gst_video_overlay_get_seqnum ();
797 GST_LOG ("new rectangle %p: %ux%u => %ux%u @ %u,%u, seq_num %u, format %u, "
798 "flags %x, pixels %p", rect, width, height, render_width, render_height,
799 render_x, render_y, rect->seq_num, rect->format, rect->flags, pixels);
805 * gst_video_overlay_rectangle_get_render_rectangle:
806 * @rectangle: a #GstVideoOverlayRectangle
807 * @render_x: (out) (allow-none): address where to store the X render offset
808 * @render_y: (out) (allow-none): address where to store the Y render offset
809 * @render_width: (out) (allow-none): address where to store the render width
810 * @render_height: (out) (allow-none): address where to store the render height
812 * Retrieves the render position and render dimension of the overlay
813 * rectangle on the video.
815 * Returns: TRUE if valid render dimensions were retrieved.
820 gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
821 rectangle, gint * render_x, gint * render_y, guint * render_width,
822 guint * render_height)
824 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), FALSE);
827 *render_x = rectangle->x;
829 *render_y = rectangle->y;
831 *render_width = rectangle->render_width;
833 *render_height = rectangle->render_height;
839 * gst_video_overlay_rectangle_set_render_rectangle:
840 * @rectangle: a #GstVideoOverlayRectangle
841 * @render_x: render X position of rectangle on video
842 * @render_y: render Y position of rectangle on video
843 * @render_width: render width of rectangle
844 * @render_height: render height of rectangle
846 * Sets the render position and dimensions of the rectangle on the video.
847 * This function is mainly for elements that modify the size of the video
848 * in some way (e.g. through scaling or cropping) and need to adjust the
849 * details of any overlays to match the operation that changed the size.
851 * @rectangle must be writable, meaning its refcount must be 1. You can
852 * make the rectangles inside a #GstVideoOverlayComposition writable using
853 * gst_video_overlay_composition_make_writable() or
854 * gst_video_overlay_composition_copy().
859 gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
860 rectangle, gint render_x, gint render_y, guint render_width,
863 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
864 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (rectangle) == 1);
866 rectangle->x = render_x;
867 rectangle->y = render_y;
868 rectangle->render_width = render_width;
869 rectangle->render_height = render_height;
873 gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
876 for (j = 0; j < info->height; ++j) {
877 guint8 *line = info->pixels + info->stride[0] * j;
878 for (i = 0; i < info->width; ++i) {
880 line[1] = line[1] * a / 255;
881 line[2] = line[2] * a / 255;
882 line[3] = line[3] * a / 255;
889 gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
892 for (j = 0; j < info->height; ++j) {
893 guint8 *line = info->pixels + info->stride[0] * j;
894 for (i = 0; i < info->width; ++i) {
897 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
898 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
899 line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
907 gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
908 rectangle, guint * stride, GstVideoOverlayFormatFlags flags,
911 GstVideoOverlayRectangle *scaled_rect = NULL;
912 GstBlendVideoFormatInfo info;
915 guint wanted_width = unscaled ? rectangle->width : rectangle->render_width;
916 guint wanted_height = unscaled ? rectangle->height : rectangle->render_height;
918 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
919 g_return_val_if_fail (stride != NULL, NULL);
920 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
922 /* This assumes we don't need to adjust the format */
923 if (wanted_width == rectangle->width &&
924 wanted_height == rectangle->height &&
925 gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
927 *stride = rectangle->stride;
928 return rectangle->pixels;
931 /* see if we've got one cached already */
932 GST_RECTANGLE_LOCK (rectangle);
933 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
934 GstVideoOverlayRectangle *r = l->data;
936 if (r->width == wanted_width &&
937 r->height == wanted_height &&
938 gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
939 /* we'll keep these rectangles around until finalize, so it's ok not
940 * to take our own ref here */
945 GST_RECTANGLE_UNLOCK (rectangle);
947 if (scaled_rect != NULL)
950 /* not cached yet, do the scaling and put the result into our cache */
951 video_blend_format_info_init (&info, GST_BUFFER_DATA (rectangle->pixels),
952 rectangle->height, rectangle->width, rectangle->format,
953 !!(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
955 if (wanted_width != rectangle->width || wanted_height != rectangle->height) {
956 video_blend_scale_linear_RGBA (&info, wanted_height, wanted_width);
958 /* if we don't have to scale, we have to modify the alpha values, so we
959 * need to make a copy of the pixel memory (and we take ownership below) */
960 info.pixels = g_memdup (info.pixels, info.size);
963 if (!gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags, flags)) {
964 if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
965 gst_video_overlay_rectangle_unpremultiply (&info);
967 gst_video_overlay_rectangle_premultiply (&info);
971 buf = gst_buffer_new ();
972 GST_BUFFER_DATA (buf) = info.pixels;
973 GST_BUFFER_MALLOCDATA (buf) = info.pixels;
974 GST_BUFFER_SIZE (buf) = info.size;
976 scaled_rect = gst_video_overlay_rectangle_new_argb (buf,
977 wanted_width, wanted_height, info.stride[0],
978 0, 0, wanted_width, wanted_height, rectangle->flags);
980 gst_buffer_unref (buf);
982 GST_RECTANGLE_LOCK (rectangle);
983 rectangle->scaled_rectangles =
984 g_list_prepend (rectangle->scaled_rectangles, scaled_rect);
985 GST_RECTANGLE_UNLOCK (rectangle);
989 *stride = scaled_rect->stride;
990 return scaled_rect->pixels;
994 * gst_video_overlay_rectangle_get_pixels_argb:
995 * @rectangle: a #GstVideoOverlayRectangle
996 * @stride: (out) (allow-none): address of guint variable where to store the
997 * row stride of the ARGB pixel data in the buffer
1000 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1001 * row stride @stride and width and height of the render dimensions as per
1002 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
1003 * not return a reference, the caller should obtain a reference of her own
1004 * with gst_buffer_ref() if needed.
1009 gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
1010 rectangle, guint * stride, GstVideoOverlayFormatFlags flags)
1012 return gst_video_overlay_rectangle_get_pixels_argb_internal (rectangle,
1013 stride, flags, FALSE);
1017 * gst_video_overlay_rectangle_get_pixels_unscaled_argb:
1018 * @rectangle: a #GstVideoOverlayRectangle
1019 * @width: (out): address where to store the width of the unscaled
1020 * rectangle in pixels
1021 * @width: (out): address where to store the height of the unscaled
1022 * rectangle in pixels
1023 * @stride: (out): address of guint variable where to store the row
1024 * stride of the ARGB pixel data in the buffer
1027 * Retrieves the pixel data as it is. This is useful if the caller can
1028 * do the scaling itself when handling the overlaying. The rectangle will
1029 * need to be scaled to the render dimensions, which can be retrieved using
1030 * gst_video_overlay_rectangle_get_render_rectangle().
1032 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1033 * row stride @stride. This function does not return a reference, the caller
1034 * should obtain a reference of her own with gst_buffer_ref() if needed.
1039 gst_video_overlay_rectangle_get_pixels_unscaled_argb (GstVideoOverlayRectangle *
1040 rectangle, guint * width, guint * height, guint * stride,
1041 GstVideoOverlayFormatFlags flags)
1043 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1044 g_return_val_if_fail (width != NULL, NULL);
1045 g_return_val_if_fail (height != NULL, NULL);
1046 g_return_val_if_fail (stride != NULL, NULL);
1048 *width = rectangle->width;
1049 *height = rectangle->height;
1050 return gst_video_overlay_rectangle_get_pixels_argb_internal (rectangle,
1051 stride, flags, TRUE);
1055 * gst_video_overlay_rectangle_get_flags:
1056 * @rectangle: a #GstVideoOverlayRectangle
1058 * Retrieves the flags associated with a #GstVideoOverlayRectangle.
1059 * This is useful if the caller can handle both premultiplied alpha and
1060 * non premultiplied alpha, for example. By knowing whether the rectangle
1061 * uses premultiplied or not, it can request the pixel data in the format
1062 * it is stored in, to avoid unnecessary conversion.
1064 * Returns: the #GstVideoOverlayFormatFlags associated with the rectangle.
1068 GstVideoOverlayFormatFlags
1069 gst_video_overlay_rectangle_get_flags (GstVideoOverlayRectangle * rectangle)
1071 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle),
1072 GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1074 return rectangle->flags;
1078 * gst_video_overlay_rectangle_copy:
1079 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to copy
1081 * Makes a copy of @rectangle, so that it is possible to modify it
1082 * (e.g. to change the render co-ordinates or render dimension). The
1083 * actual overlay pixel data buffers contained in the rectangle are not
1086 * Returns: (transfer full): a new #GstVideoOverlayRectangle equivalent
1091 GstVideoOverlayRectangle *
1092 gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
1094 GstVideoOverlayRectangle *copy;
1096 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1098 copy = gst_video_overlay_rectangle_new_argb (rectangle->pixels,
1099 rectangle->width, rectangle->height, rectangle->stride,
1100 rectangle->x, rectangle->y,
1101 rectangle->render_width, rectangle->render_height, rectangle->flags);
1107 * gst_video_overlay_rectangle_get_seqnum:
1108 * @rectangle: a #GstVideoOverlayRectangle
1110 * Returns the sequence number of this rectangle. Sequence numbers are
1111 * monotonically increasing and unique for overlay compositions and rectangles
1112 * (meaning there will never be a rectangle with the same sequence number as
1115 * Returns: the sequence number of @rectangle
1120 gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)
1122 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), 0);
1124 return rectangle->seq_num;