/** * gst_vaapi_surface_set_subpictures_from_composition: * @surface: a #GstVaapiSurface * @compostion: a #GstVideoOverlayCompositon * @propagate_context: a flag specifying whether to apply composition * to the parent context, if any * * Helper to update the subpictures from #GstVideoOverlayCompositon. Sending * a NULL composition will clear all the current subpictures. Note that this * method will clear existing subpictures. * * Return value: %TRUE on success */ gboolean gst_vaapi_surface_set_subpictures_from_composition( GstVaapiSurface *surface, GstVideoOverlayComposition *composition, gboolean propagate_context ) { GstVaapiDisplay *display; guint n, nb_rectangles; g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE); if (propagate_context) { GstVaapiContext * const context = surface->priv->parent_context; if (context) return gst_vaapi_context_apply_composition(context, composition); } display = GST_VAAPI_OBJECT_DISPLAY(surface); if (!display) return FALSE; /* Clear current subpictures */ gst_vaapi_surface_destroy_subpictures(surface); if (!composition) return TRUE; nb_rectangles = gst_video_overlay_composition_n_rectangles (composition); /* Overlay all the rectangles cantained in the overlay composition */ for (n = 0; n < nb_rectangles; ++n) { GstVideoOverlayRectangle *rect; GstVaapiRectangle sub_rect; GstVaapiSubpicture *subpicture; rect = gst_video_overlay_composition_get_rectangle (composition, n); subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle (display, rect); gst_video_overlay_rectangle_get_render_rectangle (rect, (gint *)&sub_rect.x, (gint *)&sub_rect.y, &sub_rect.width, &sub_rect.height); if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, NULL, &sub_rect)) { GST_WARNING ("could not render overlay rectangle %p", rect); g_object_unref (subpicture); return FALSE; } g_object_unref (subpicture); } return TRUE; }
static gboolean _is_overlay_in_rectangles (GstVideoOverlayComposition * composition, GstGLCompositionOverlay * overlay) { guint i; for (i = 0; i < gst_video_overlay_composition_n_rectangles (composition); i++) { GstVideoOverlayRectangle *rectangle = gst_video_overlay_composition_get_rectangle (composition, i); if (overlay->rectangle == rectangle) return TRUE; } return FALSE; }
void gst_gl_overlay_compositor_upload_overlays (GstGLOverlayCompositor * compositor, GstBuffer * buf) { GstVideoOverlayCompositionMeta *composition_meta; composition_meta = gst_buffer_get_video_overlay_composition_meta (buf); if (composition_meta) { GstVideoOverlayComposition *composition = NULL; guint num_overlays, i; GList *l = compositor->overlays; GST_DEBUG ("GstVideoOverlayCompositionMeta found."); composition = composition_meta->overlay; num_overlays = gst_video_overlay_composition_n_rectangles (composition); /* add new overlays to list */ for (i = 0; i < num_overlays; i++) { GstVideoOverlayRectangle *rectangle = gst_video_overlay_composition_get_rectangle (composition, i); if (!_is_rectangle_in_overlays (compositor->overlays, rectangle)) { GstGLCompositionOverlay *overlay = gst_gl_composition_overlay_new (compositor->context, rectangle, compositor->position_attrib, compositor->texcoord_attrib); gst_object_ref_sink (overlay); gst_gl_composition_overlay_upload (overlay, buf); compositor->overlays = g_list_append (compositor->overlays, overlay); } } /* remove old overlays from list */ while (l != NULL) { GList *next = l->next; GstGLCompositionOverlay *overlay = (GstGLCompositionOverlay *) l->data; if (!_is_overlay_in_rectangles (composition, overlay)) { compositor->overlays = g_list_delete_link (compositor->overlays, l); gst_object_unref (overlay); } l = next; } } else { gst_gl_overlay_compositor_free_overlays (compositor); } }
static GstFlowReturn gst_overlay_composition_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstOverlayComposition *self = GST_OVERLAY_COMPOSITION (parent); GstVideoOverlayComposition *compo = NULL; GstVideoOverlayCompositionMeta *upstream_compo_meta; if (gst_pad_check_reconfigure (self->srcpad)) { if (!gst_overlay_composition_negotiate (self, NULL)) { gst_pad_mark_reconfigure (self->srcpad); gst_buffer_unref (buffer); GST_OBJECT_LOCK (self->srcpad); if (GST_PAD_IS_FLUSHING (self->srcpad)) { GST_OBJECT_UNLOCK (self->srcpad); return GST_FLOW_FLUSHING; } GST_OBJECT_UNLOCK (self->srcpad); return GST_FLOW_NOT_NEGOTIATED; } } if (!self->sample) { self->sample = gst_sample_new (buffer, self->caps, &self->segment, NULL); } else { self->sample = gst_sample_make_writable (self->sample); gst_sample_set_buffer (self->sample, buffer); gst_sample_set_caps (self->sample, self->caps); gst_sample_set_segment (self->sample, &self->segment); } g_signal_emit (self, overlay_composition_signals[SIGNAL_DRAW], 0, self->sample, &compo); /* Don't store the buffer in the sample any longer, otherwise it will not * be writable below as we have one reference in the sample and one in * this function. * * If the sample is not writable itself then the application kept an * reference itself. */ if (gst_sample_is_writable (self->sample)) { gst_sample_set_buffer (self->sample, NULL); } if (!compo) { GST_DEBUG_OBJECT (self->sinkpad, "Application did not provide an overlay composition"); return gst_pad_push (self->srcpad, buffer); } /* If upstream attached a meta, we can safely add our own things * in it. Upstream must've checked that downstream supports it */ upstream_compo_meta = gst_buffer_get_video_overlay_composition_meta (buffer); if (upstream_compo_meta) { GstVideoOverlayComposition *merged_compo = gst_video_overlay_composition_copy (upstream_compo_meta->overlay); guint i, n; GST_DEBUG_OBJECT (self->sinkpad, "Appending to upstream overlay composition"); n = gst_video_overlay_composition_n_rectangles (compo); for (i = 0; i < n; i++) { GstVideoOverlayRectangle *rect = gst_video_overlay_composition_get_rectangle (compo, i); gst_video_overlay_composition_add_rectangle (merged_compo, rect); } gst_video_overlay_composition_unref (compo); gst_video_overlay_composition_unref (upstream_compo_meta->overlay); upstream_compo_meta->overlay = merged_compo; } else if (self->attach_compo_to_buffer) { GST_DEBUG_OBJECT (self->sinkpad, "Attaching as meta"); buffer = gst_buffer_make_writable (buffer); gst_buffer_add_video_overlay_composition_meta (buffer, compo); gst_video_overlay_composition_unref (compo); } else { GstVideoFrame frame; buffer = gst_buffer_make_writable (buffer); if (!gst_video_frame_map (&frame, &self->info, buffer, GST_MAP_READWRITE)) { gst_video_overlay_composition_unref (compo); goto map_failed; } gst_video_overlay_composition_blend (compo, &frame); gst_video_frame_unmap (&frame); gst_video_overlay_composition_unref (compo); } return gst_pad_push (self->srcpad, buffer); map_failed: { GST_ERROR_OBJECT (self->sinkpad, "Failed to map buffer"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } }