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
141 GList *scaled_rectangles;
144 struct _GstVideoOverlayRectangleClass
146 GstMiniObjectClass parent_class;
149 #define GST_RECTANGLE_LOCK(rect) g_mutex_lock(&rect->lock)
150 #define GST_RECTANGLE_UNLOCK(rect) g_mutex_unlock(&rect->lock)
152 static void gst_video_overlay_composition_class_init (GstMiniObjectClass * k);
153 static void gst_video_overlay_composition_finalize (GstMiniObject * comp);
154 static void gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass);
155 static void gst_video_overlay_rectangle_finalize (GstMiniObject * rect);
157 /* --------------------------- utility functions --------------------------- */
159 #ifndef GST_DISABLE_GST_DEBUG
161 #define GST_CAT_DEFAULT ensure_debug_category()
163 static GstDebugCategory *
164 ensure_debug_category (void)
166 static gsize cat_gonce = 0;
168 if (g_once_init_enter (&cat_gonce)) {
171 cat_done = (gsize) _gst_debug_category_new ("video-composition", 0,
172 "video overlay composition");
174 g_once_init_leave (&cat_gonce, cat_done);
177 return (GstDebugCategory *) cat_gonce;
182 #define ensure_debug_category() /* NOOP */
184 #endif /* GST_DISABLE_GST_DEBUG */
187 gst_video_overlay_get_seqnum (void)
189 static gint seqnum; /* 0 */
191 return (guint) g_atomic_int_add (&seqnum, 1);
194 #define GST_OVERLAY_COMPOSITION_QUARK gst_overlay_composition_quark_get()
196 gst_overlay_composition_quark_get (void)
198 static gsize quark_gonce = 0;
200 if (g_once_init_enter (&quark_gonce)) {
203 quark = (gsize) g_quark_from_static_string ("GstVideoOverlayComposition");
205 g_once_init_leave (&quark_gonce, quark);
208 return (GQuark) quark_gonce;
211 #define COMPOSITION_QUARK composition_quark_get()
213 composition_quark_get (void)
215 static gsize quark_gonce = 0;
217 if (g_once_init_enter (&quark_gonce)) {
220 quark = (gsize) g_quark_from_static_string ("composition");
222 g_once_init_leave (&quark_gonce, quark);
225 return (GQuark) quark_gonce;
229 * gst_video_buffer_set_overlay_composition:
231 * @comp: (allow-none): a #GstVideoOverlayComposition, or NULL to clear a
232 * previously-set composition
234 * Sets an overlay composition on a buffer. The buffer will obtain its own
235 * reference to the composition, meaning this function does not take ownership
241 gst_video_buffer_set_overlay_composition (GstBuffer * buf,
242 GstVideoOverlayComposition * comp)
244 gst_buffer_set_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK,
245 gst_structure_id_new (GST_OVERLAY_COMPOSITION_QUARK,
246 COMPOSITION_QUARK, GST_TYPE_VIDEO_OVERLAY_COMPOSITION, comp, NULL));
250 * gst_video_buffer_get_overlay_composition:
253 * Get the overlay composition that has previously been attached to a buffer
254 * with gst_video_buffer_get_overlay_composition(), usually by another element
257 * Returns: (transfer none): the #GstVideoOverlayComposition attached to
258 * this buffer, or NULL. Does not return a reference to the composition,
259 * caller must obtain her own ref via gst_video_overlay_composition_ref()
264 GstVideoOverlayComposition *
265 gst_video_buffer_get_overlay_composition (GstBuffer * buf)
267 const GstStructure *s;
270 s = gst_buffer_get_qdata (buf, GST_OVERLAY_COMPOSITION_QUARK);
274 val = gst_structure_id_get_value (s, COMPOSITION_QUARK);
278 return GST_VIDEO_OVERLAY_COMPOSITION (gst_value_get_mini_object (val));
281 /* ------------------------------ composition ------------------------------ */
283 #define RECTANGLE_ARRAY_STEP 4 /* premature optimization */
286 gst_video_overlay_composition_get_type (void)
288 static volatile gsize type_id = 0;
290 if (g_once_init_enter (&type_id)) {
291 GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
292 g_intern_static_string ("GstVideoOverlayComposition"),
293 sizeof (GstVideoOverlayCompositionClass),
294 (GClassInitFunc) gst_video_overlay_composition_class_init,
295 sizeof (GstVideoOverlayComposition),
299 g_once_init_leave (&type_id, new_type_id);
306 gst_video_overlay_composition_finalize (GstMiniObject * mini_obj)
308 GstVideoOverlayComposition *comp = (GstVideoOverlayComposition *) mini_obj;
311 num = comp->num_rectangles;
314 gst_video_overlay_rectangle_unref (comp->rectangles[num - 1]);
318 g_free (comp->rectangles);
319 comp->rectangles = NULL;
320 comp->num_rectangles = 0;
322 /* not chaining up to GstMiniObject's finalize for now, we know it's empty */
326 gst_video_overlay_composition_class_init (GstMiniObjectClass * klass)
328 klass->finalize = gst_video_overlay_composition_finalize;
329 klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_composition_copy;
333 * gst_video_overlay_composition_new:
334 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
337 * Creates a new video overlay composition object to hold one or more
338 * overlay rectangles.
340 * Returns: (transfer full): a new #GstVideoOverlayComposition. Unref with
341 * gst_video_overlay_composition_unref() when no longer needed.
345 GstVideoOverlayComposition *
346 gst_video_overlay_composition_new (GstVideoOverlayRectangle * rectangle)
348 GstVideoOverlayComposition *comp;
351 /* FIXME: should we allow empty compositions? Could also be expressed as
352 * buffer without a composition on it. Maybe there are cases where doing
353 * an empty new + _add() in a loop is easier? */
354 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
356 comp = (GstVideoOverlayComposition *)
357 gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_COMPOSITION);
359 comp->rectangles = g_new0 (GstVideoOverlayRectangle *, RECTANGLE_ARRAY_STEP);
360 comp->rectangles[0] = gst_video_overlay_rectangle_ref (rectangle);
361 comp->num_rectangles = 1;
363 comp->seq_num = gst_video_overlay_get_seqnum ();
365 /* since the rectangle was created earlier, its seqnum is smaller than ours */
366 comp->min_seq_num_used = rectangle->seq_num;
368 GST_LOG ("new composition %p: seq_num %u with rectangle %p", comp,
369 comp->seq_num, rectangle);
375 * gst_video_overlay_composition_add_rectangle:
376 * @comp: a #GstVideoOverlayComposition
377 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to add to the
380 * Adds an overlay rectangle to an existing overlay composition object. This
381 * must be done right after creating the overlay composition.
386 gst_video_overlay_composition_add_rectangle (GstVideoOverlayComposition * comp,
387 GstVideoOverlayRectangle * rectangle)
389 g_return_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp));
390 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
391 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1);
393 if (comp->num_rectangles % RECTANGLE_ARRAY_STEP == 0) {
395 g_renew (GstVideoOverlayRectangle *, comp->rectangles,
396 comp->num_rectangles + RECTANGLE_ARRAY_STEP);
399 comp->rectangles[comp->num_rectangles] =
400 gst_video_overlay_rectangle_ref (rectangle);
401 comp->num_rectangles += 1;
403 comp->min_seq_num_used = MIN (comp->min_seq_num_used, rectangle->seq_num);
405 GST_LOG ("composition %p: added rectangle %p", comp, rectangle);
409 * gst_video_overlay_composition_n_rectangles:
410 * @comp: a #GstVideoOverlayComposition
412 * Returns the number of #GstVideoOverlayRectangle<!-- -->s contained in @comp.
414 * Returns: the number of rectangles
419 gst_video_overlay_composition_n_rectangles (GstVideoOverlayComposition * comp)
421 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
423 return comp->num_rectangles;
427 * gst_video_overlay_composition_get_rectangle:
428 * @comp: a #GstVideoOverlayComposition
429 * @n: number of the rectangle to get
431 * Returns the @n-th #GstVideoOverlayRectangle contained in @comp.
433 * Returns: (transfer none): the @n-th rectangle, or NULL if @n is out of
434 * bounds. Will not return a new reference, the caller will need to
435 * obtain her own reference using gst_video_overlay_rectangle_ref()
440 GstVideoOverlayRectangle *
441 gst_video_overlay_composition_get_rectangle (GstVideoOverlayComposition * comp,
444 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
446 if (n >= comp->num_rectangles)
449 return comp->rectangles[n];
453 gst_video_overlay_rectangle_needs_scaling (GstVideoOverlayRectangle * r)
455 return (r->width != r->render_width || r->height != r->render_height);
459 * gst_video_overlay_composition_blend:
460 * @comp: a #GstVideoOverlayComposition
461 * @video_buf: a #GstBuffer containing raw video data in a supported format
463 * Blends the overlay rectangles in @comp on top of the raw video data
464 * contained in @video_buf. The data in @video_buf must be writable. If
465 * needed, use gst_buffer_make_writable() before calling this function to
466 * ensure a buffer is writable. @video_buf must also have valid raw video
472 gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
473 GstBuffer * video_buf)
475 GstBlendVideoFormatInfo video_info, rectangle_info;
481 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), FALSE);
482 g_return_val_if_fail (GST_IS_BUFFER (video_buf), FALSE);
483 g_return_val_if_fail (gst_buffer_is_writable (video_buf), FALSE);
484 g_return_val_if_fail (GST_BUFFER_CAPS (video_buf) != NULL, FALSE);
486 if (!gst_video_format_parse_caps (GST_BUFFER_CAPS (video_buf), &fmt, &w, &h)) {
487 gchar *str = gst_caps_to_string (GST_BUFFER_CAPS (video_buf));
488 g_warning ("%s: could not parse video buffer caps '%s'", GST_FUNCTION, str);
493 video_blend_format_info_init (&video_info, GST_BUFFER_DATA (video_buf),
496 num = comp->num_rectangles;
497 GST_LOG ("Blending composition %p with %u rectangles onto video buffer %p "
498 "(%ux%u, format %u)", comp, num, video_buf, w, h, fmt);
500 for (n = 0; n < num; ++n) {
501 GstVideoOverlayRectangle *rect;
502 gboolean needs_scaling;
504 rect = comp->rectangles[n];
506 GST_LOG (" rectangle %u %p: %ux%u, format %u", n, rect, rect->height,
507 rect->width, rect->format);
509 video_blend_format_info_init (&rectangle_info,
510 GST_BUFFER_DATA (rect->pixels), rect->height, rect->width,
512 ! !(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
514 needs_scaling = gst_video_overlay_rectangle_needs_scaling (rect);
516 video_blend_scale_linear_RGBA (&rectangle_info, rect->render_height,
520 ret = video_blend (&video_info, &rectangle_info, rect->x, rect->y);
522 GST_WARNING ("Could not blend overlay rectangle onto video buffer");
525 /* FIXME: should cache scaled pixels in the rectangle struct */
527 g_free (rectangle_info.pixels);
534 * gst_video_overlay_composition_copy:
535 * @comp: (transfer none): a #GstVideoOverlayComposition to copy
537 * Makes a copy of @comp and all contained rectangles, so that it is possible
538 * to modify the composition and contained rectangles (e.g. add additional
539 * rectangles or change the render co-ordinates or render dimension). The
540 * actual overlay pixel data buffers contained in the rectangles are not
543 * Returns: (transfer full): a new #GstVideoOverlayComposition equivalent
548 GstVideoOverlayComposition *
549 gst_video_overlay_composition_copy (GstVideoOverlayComposition * comp)
551 GstVideoOverlayComposition *copy;
552 GstVideoOverlayRectangle *rect;
555 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
557 if (G_LIKELY (comp->num_rectangles == 0))
558 return gst_video_overlay_composition_new (NULL);
560 rect = gst_video_overlay_rectangle_copy (comp->rectangles[0]);
561 copy = gst_video_overlay_composition_new (rect);
562 gst_video_overlay_rectangle_unref (rect);
564 for (n = 1; n < comp->num_rectangles; ++n) {
565 rect = gst_video_overlay_rectangle_copy (comp->rectangles[n]);
566 gst_video_overlay_composition_add_rectangle (copy, rect);
567 gst_video_overlay_rectangle_unref (rect);
574 * gst_video_overlay_composition_make_writable:
575 * @comp: (transfer full): a #GstVideoOverlayComposition to copy
577 * Takes ownership of @comp and returns a version of @comp that is writable
578 * (i.e. can be modified). Will either return @comp right away, or create a
579 * new writable copy of @comp and unref @comp itself. All the contained
580 * rectangles will also be copied, but the actual overlay pixel data buffers
581 * contained in the rectangles are not copied.
583 * Returns: (transfer full): a writable #GstVideoOverlayComposition
584 * equivalent to @comp.
588 GstVideoOverlayComposition *
589 gst_video_overlay_composition_make_writable (GstVideoOverlayComposition * comp)
591 GstVideoOverlayComposition *writable_comp;
593 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), NULL);
595 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp) == 1) {
598 for (n = 0; n < comp->num_rectangles; ++n) {
599 if (GST_MINI_OBJECT_REFCOUNT_VALUE (comp->rectangles[n]) != 1)
607 writable_comp = gst_video_overlay_composition_copy (comp);
608 gst_video_overlay_composition_unref (comp);
610 return writable_comp;
614 * gst_video_overlay_composition_get_seqnum:
615 * @comp: a #GstVideoOverlayComposition
617 * Returns the sequence number of this composition. Sequence numbers are
618 * monotonically increasing and unique for overlay compositions and rectangles
619 * (meaning there will never be a rectangle with the same sequence number as
622 * Returns: the sequence number of @comp
627 gst_video_overlay_composition_get_seqnum (GstVideoOverlayComposition * comp)
629 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_COMPOSITION (comp), 0);
631 return comp->seq_num;
634 /* ------------------------------ rectangles ------------------------------ -*/
636 static void gst_video_overlay_rectangle_instance_init (GstMiniObject * miniobj);
639 gst_video_overlay_rectangle_get_type (void)
641 static volatile gsize type_id = 0;
643 if (g_once_init_enter (&type_id)) {
644 GType new_type_id = g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
645 g_intern_static_string ("GstVideoOverlayRectangle"),
646 sizeof (GstVideoOverlayRectangleClass),
647 (GClassInitFunc) gst_video_overlay_rectangle_class_init,
648 sizeof (GstVideoOverlayRectangle),
649 (GInstanceInitFunc) gst_video_overlay_rectangle_instance_init,
652 g_once_init_leave (&type_id, new_type_id);
659 gst_video_overlay_rectangle_finalize (GstMiniObject * mini_obj)
661 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
663 gst_buffer_replace (&rect->pixels, NULL);
665 while (rect->scaled_rectangles != NULL) {
666 GstVideoOverlayRectangle *scaled_rect = rect->scaled_rectangles->data;
668 gst_video_overlay_rectangle_unref (scaled_rect);
670 rect->scaled_rectangles =
671 g_list_delete_link (rect->scaled_rectangles, rect->scaled_rectangles);
673 g_mutex_clear (&rect->lock);
675 /* not chaining up to GstMiniObject's finalize for now, we know it's empty */
679 gst_video_overlay_rectangle_class_init (GstMiniObjectClass * klass)
681 klass->finalize = gst_video_overlay_rectangle_finalize;
682 klass->copy = (GstMiniObjectCopyFunction) gst_video_overlay_rectangle_copy;
686 gst_video_overlay_rectangle_instance_init (GstMiniObject * mini_obj)
688 GstVideoOverlayRectangle *rect = (GstVideoOverlayRectangle *) mini_obj;
690 g_mutex_init (&rect->lock);
693 static inline gboolean
694 gst_video_overlay_rectangle_check_flags (GstVideoOverlayFormatFlags flags)
696 /* Check flags only contains flags we know about */
697 return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) == 0;
701 gst_video_overlay_rectangle_is_same_alpha_type (GstVideoOverlayFormatFlags
702 flags1, GstVideoOverlayFormatFlags flags2)
704 return ((flags1 ^ flags2) & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
710 * gst_video_overlay_rectangle_new_argb:
711 * @pixels: (transfer none): a #GstBuffer pointing to the pixel memory
712 * @width: the width of the rectangle in @pixels
713 * @height: the height of the rectangle in @pixels
714 * @stride: the stride of the rectangle in @pixels in bytes (>= 4*width)
715 * @render_x: the X co-ordinate on the video where the top-left corner of this
716 * overlay rectangle should be rendered to
717 * @render_y: the Y co-ordinate on the video where the top-left corner of this
718 * overlay rectangle should be rendered to
719 * @render_width: the render width of this rectangle on the video
720 * @render_height: the render height of this rectangle on the video
723 * Creates a new video overlay rectangle with ARGB pixel data. The layout
724 * of the components in memory is B-G-R-A on little-endian platforms
725 * (corresponding to #GST_VIDEO_FORMAT_BGRA) and A-R-G-B on big-endian
726 * platforms (corresponding to #GST_VIDEO_FORMAT_ARGB). In other words,
727 * pixels are treated as 32-bit words and the lowest 8 bits then contain
728 * the blue component value and the highest 8 bits contain the alpha
729 * component value. Unless specified in the flags, the RGB values are
730 * non-premultiplied. This is the format that is used by most hardware,
731 * and also many rendering libraries such as Cairo, for example.
733 * Returns: (transfer full): a new #GstVideoOverlayRectangle. Unref with
734 * gst_video_overlay_rectangle_unref() when no longer needed.
738 GstVideoOverlayRectangle *
739 gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
740 guint width, guint height, guint stride, gint render_x, gint render_y,
741 guint render_width, guint render_height, GstVideoOverlayFormatFlags flags)
743 GstVideoOverlayRectangle *rect;
745 g_return_val_if_fail (GST_IS_BUFFER (pixels), NULL);
746 /* technically ((height-1)*stride)+width might be okay too */
747 g_return_val_if_fail (GST_BUFFER_SIZE (pixels) >= height * stride, NULL);
748 g_return_val_if_fail (stride >= (4 * width), NULL);
749 g_return_val_if_fail (height > 0 && width > 0, NULL);
750 g_return_val_if_fail (render_height > 0 && render_width > 0, NULL);
751 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
753 rect = (GstVideoOverlayRectangle *)
754 gst_mini_object_new (GST_TYPE_VIDEO_OVERLAY_RECTANGLE);
756 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
757 rect->format = GST_VIDEO_FORMAT_BGRA;
759 rect->format = GST_VIDEO_FORMAT_ARGB;
762 rect->pixels = gst_buffer_ref (pixels);
765 rect->height = height;
766 rect->stride = stride;
770 rect->render_width = render_width;
771 rect->render_height = render_height;
775 rect->seq_num = gst_video_overlay_get_seqnum ();
777 GST_LOG ("new rectangle %p: %ux%u => %ux%u @ %u,%u, seq_num %u, format %u, "
778 "flags %x, pixels %p", rect, width, height, render_width, render_height,
779 render_x, render_y, rect->seq_num, rect->format, rect->flags, pixels);
785 * gst_video_overlay_rectangle_get_render_rectangle:
786 * @rectangle: a #GstVideoOverlayRectangle
787 * @render_x: (out) (allow-none): address where to store the X render offset
788 * @render_y: (out) (allow-none): address where to store the Y render offset
789 * @render_width: (out) (allow-none): address where to store the render width
790 * @render_height: (out) (allow-none): address where to store the render height
792 * Retrieves the render position and render dimension of the overlay
793 * rectangle on the video.
795 * Returns: TRUE if valid render dimensions were retrieved.
800 gst_video_overlay_rectangle_get_render_rectangle (GstVideoOverlayRectangle *
801 rectangle, gint * render_x, gint * render_y, guint * render_width,
802 guint * render_height)
804 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), FALSE);
807 *render_x = rectangle->x;
809 *render_y = rectangle->y;
811 *render_width = rectangle->render_width;
813 *render_height = rectangle->render_height;
819 * gst_video_overlay_rectangle_set_render_rectangle:
820 * @rectangle: a #GstVideoOverlayRectangle
821 * @render_x: render X position of rectangle on video
822 * @render_y: render Y position of rectangle on video
823 * @render_width: render width of rectangle
824 * @render_height: render height of rectangle
826 * Sets the render position and dimensions of the rectangle on the video.
827 * This function is mainly for elements that modify the size of the video
828 * in some way (e.g. through scaling or cropping) and need to adjust the
829 * details of any overlays to match the operation that changed the size.
831 * @rectangle must be writable, meaning its refcount must be 1. You can
832 * make the rectangles inside a #GstVideoOverlayComposition writable using
833 * gst_video_overlay_composition_make_writable() or
834 * gst_video_overlay_composition_copy().
839 gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
840 rectangle, gint render_x, gint render_y, guint render_width,
843 g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
844 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (rectangle) == 1);
846 rectangle->x = render_x;
847 rectangle->y = render_y;
848 rectangle->render_width = render_width;
849 rectangle->render_height = render_height;
853 gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
856 for (j = 0; j < info->height; ++j) {
857 guint8 *line = info->pixels + info->stride[0] * j;
858 for (i = 0; i < info->width; ++i) {
860 line[1] = line[1] * a / 255;
861 line[2] = line[2] * a / 255;
862 line[3] = line[3] * a / 255;
869 gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
872 for (j = 0; j < info->height; ++j) {
873 guint8 *line = info->pixels + info->stride[0] * j;
874 for (i = 0; i < info->width; ++i) {
877 line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
878 line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
879 line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
887 gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
888 rectangle, guint * stride, GstVideoOverlayFormatFlags flags,
891 GstVideoOverlayRectangle *scaled_rect = NULL;
892 GstBlendVideoFormatInfo info;
895 guint wanted_width = unscaled ? rectangle->width : rectangle->render_width;
896 guint wanted_height = unscaled ? rectangle->height : rectangle->render_height;
898 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
899 g_return_val_if_fail (stride != NULL, NULL);
900 g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
902 /* This assumes we don't need to adjust the format */
903 if (wanted_width == rectangle->width &&
904 wanted_height == rectangle->height &&
905 gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
907 *stride = rectangle->stride;
908 return rectangle->pixels;
911 /* see if we've got one cached already */
912 GST_RECTANGLE_LOCK (rectangle);
913 for (l = rectangle->scaled_rectangles; l != NULL; l = l->next) {
914 GstVideoOverlayRectangle *r = l->data;
916 if (r->width == wanted_width &&
917 r->height == wanted_height &&
918 gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
920 /* we'll keep these rectangles around until finalize, so it's ok not
921 * to take our own ref here */
926 GST_RECTANGLE_UNLOCK (rectangle);
928 if (scaled_rect != NULL)
931 /* not cached yet, do the scaling and put the result into our cache */
932 video_blend_format_info_init (&info, GST_BUFFER_DATA (rectangle->pixels),
933 rectangle->height, rectangle->width, rectangle->format,
934 ! !(rectangle->flags &
935 GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
937 if (wanted_width != rectangle->width || wanted_height != rectangle->height) {
938 video_blend_scale_linear_RGBA (&info, wanted_height, wanted_width);
941 if (!gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags, flags)) {
942 if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
943 gst_video_overlay_rectangle_unpremultiply (&info);
945 gst_video_overlay_rectangle_premultiply (&info);
949 buf = gst_buffer_new ();
950 GST_BUFFER_DATA (buf) = info.pixels;
951 GST_BUFFER_MALLOCDATA (buf) = info.pixels;
952 GST_BUFFER_SIZE (buf) = info.size;
954 scaled_rect = gst_video_overlay_rectangle_new_argb (buf,
955 wanted_width, wanted_height, info.stride[0],
956 0, 0, wanted_width, wanted_height, rectangle->flags);
958 gst_buffer_unref (buf);
960 GST_RECTANGLE_LOCK (rectangle);
961 rectangle->scaled_rectangles =
962 g_list_prepend (rectangle->scaled_rectangles, scaled_rect);
963 GST_RECTANGLE_UNLOCK (rectangle);
967 *stride = scaled_rect->stride;
968 return scaled_rect->pixels;
972 * gst_video_overlay_rectangle_get_pixels_argb:
973 * @rectangle: a #GstVideoOverlayRectangle
974 * @stride: (out) (allow-none): address of guint variable where to store the
975 * row stride of the ARGB pixel data in the buffer
978 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
979 * row stride @stride and width and height of the render dimensions as per
980 * gst_video_overlay_rectangle_get_render_rectangle(). This function does
981 * not return a reference, the caller should obtain a reference of her own
982 * with gst_buffer_ref() if needed.
987 gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
988 rectangle, guint * stride, GstVideoOverlayFormatFlags flags)
990 return gst_video_overlay_rectangle_get_pixels_argb_internal (rectangle,
991 stride, flags, FALSE);
995 * gst_video_overlay_rectangle_get_pixels_unscaled_argb:
996 * @rectangle: a #GstVideoOverlayRectangle
997 * @width: (out): address where to store the width of the unscaled
998 * rectangle in pixels
999 * @height: (out): address where to store the height of the unscaled
1000 * rectangle in pixels
1001 * @stride: (out): address of guint variable where to store the row
1002 * stride of the ARGB pixel data in the buffer
1005 * Retrieves the pixel data as it is. This is useful if the caller can
1006 * do the scaling itself when handling the overlaying. The rectangle will
1007 * need to be scaled to the render dimensions, which can be retrieved using
1008 * gst_video_overlay_rectangle_get_render_rectangle().
1010 * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
1011 * row stride @stride. This function does not return a reference, the caller
1012 * should obtain a reference of her own with gst_buffer_ref() if needed.
1017 gst_video_overlay_rectangle_get_pixels_unscaled_argb (GstVideoOverlayRectangle *
1018 rectangle, guint * width, guint * height, guint * stride,
1019 GstVideoOverlayFormatFlags flags)
1021 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1022 g_return_val_if_fail (width != NULL, NULL);
1023 g_return_val_if_fail (height != NULL, NULL);
1024 g_return_val_if_fail (stride != NULL, NULL);
1026 *width = rectangle->width;
1027 *height = rectangle->height;
1028 return gst_video_overlay_rectangle_get_pixels_argb_internal (rectangle,
1029 stride, flags, TRUE);
1033 * gst_video_overlay_rectangle_get_flags:
1034 * @rectangle: a #GstVideoOverlayRectangle
1036 * Retrieves the flags associated with a #GstVideoOverlayRectangle.
1037 * This is useful if the caller can handle both premultiplied alpha and
1038 * non premultiplied alpha, for example. By knowing whether the rectangle
1039 * uses premultiplied or not, it can request the pixel data in the format
1040 * it is stored in, to avoid unnecessary conversion.
1042 * Returns: the #GstVideoOverlayFormatFlags associated with the rectangle.
1046 GstVideoOverlayFormatFlags
1047 gst_video_overlay_rectangle_get_flags (GstVideoOverlayRectangle * rectangle)
1049 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle),
1050 GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
1052 return rectangle->flags;
1056 * gst_video_overlay_rectangle_copy:
1057 * @rectangle: (transfer none): a #GstVideoOverlayRectangle to copy
1059 * Makes a copy of @rectangle, so that it is possible to modify it
1060 * (e.g. to change the render co-ordinates or render dimension). The
1061 * actual overlay pixel data buffers contained in the rectangle are not
1064 * Returns: (transfer full): a new #GstVideoOverlayRectangle equivalent
1069 GstVideoOverlayRectangle *
1070 gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
1072 GstVideoOverlayRectangle *copy;
1074 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
1076 copy = gst_video_overlay_rectangle_new_argb (rectangle->pixels,
1077 rectangle->width, rectangle->height, rectangle->stride,
1078 rectangle->x, rectangle->y,
1079 rectangle->render_width, rectangle->render_height, rectangle->flags);
1085 * gst_video_overlay_rectangle_get_seqnum:
1086 * @rectangle: a #GstVideoOverlayRectangle
1088 * Returns the sequence number of this rectangle. Sequence numbers are
1089 * monotonically increasing and unique for overlay compositions and rectangles
1090 * (meaning there will never be a rectangle with the same sequence number as
1093 * Returns: the sequence number of @rectangle
1098 gst_video_overlay_rectangle_get_seqnum (GstVideoOverlayRectangle * rectangle)
1100 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), 0);
1102 return rectangle->seq_num;