diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11overlaycompositor.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11overlaycompositor.cpp index 64b0f731cc..d2d737a40c 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11overlaycompositor.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11overlaycompositor.cpp @@ -24,6 +24,9 @@ #include "gstd3d11overlaycompositor.h" #include "gstd3d11pluginutils.h" #include +#include +#include +#include GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_overlay_compositor_debug); #define GST_CAT_DEFAULT gst_d3d11_overlay_compositor_debug @@ -95,7 +98,23 @@ static const gchar templ_vertex_shader[] = "{\n" " return input;\n" "}\n"; -/* *INDENT-ON* */ + +struct GstD3D11CompositionOverlay +{ + ~GstD3D11CompositionOverlay () + { + if (overlay_rect) + gst_video_overlay_rectangle_unref (overlay_rect); + } + + GstVideoOverlayRectangle *overlay_rect = nullptr; + ComPtr texture; + ComPtr srv; + ComPtr vertex_buffer; + gboolean premul_alpha = FALSE; +}; + +typedef std::shared_ptr GstD3D11CompositionOverlayPtr; struct _GstD3D11OverlayCompositorPrivate { @@ -103,33 +122,22 @@ struct _GstD3D11OverlayCompositorPrivate D3D11_VIEWPORT viewport; - ID3D11PixelShader *ps; - ID3D11PixelShader *premul_ps; - ID3D11VertexShader *vs; - ID3D11InputLayout *layout; - ID3D11SamplerState *sampler; - ID3D11BlendState *blend; - ID3D11Buffer *index_buffer; + ComPtr ps; + ComPtr premul_ps; + ComPtr vs; + ComPtr layout; + ComPtr sampler; + ComPtr blend; + ComPtr index_buffer; - /* GstD3D11CompositionOverlay */ - GList *overlays; + std::vector overlays; }; +/* *INDENT-ON* */ -typedef struct -{ - GstVideoOverlayRectangle *overlay_rect; - ID3D11Texture2D *texture; - ID3D11ShaderResourceView *srv; - ID3D11Buffer *vertex_buffer; - gboolean premul_alpha; -} GstD3D11CompositionOverlay; - -static void gst_d3d11_overlay_compositor_dispose (GObject * object); -static void -gst_d3d11_overlay_compositor_free_overlays (GstD3D11OverlayCompositor * self); +static void gst_d3d11_overlay_compositor_finalize (GObject * object); #define gst_d3d11_overlay_compositor_parent_class parent_class -G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11OverlayCompositor, +G_DEFINE_TYPE (GstD3D11OverlayCompositor, gst_d3d11_overlay_compositor, GST_TYPE_OBJECT); static void @@ -137,43 +145,32 @@ gst_d3d11_overlay_compositor_class_init (GstD3D11OverlayCompositorClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->dispose = gst_d3d11_overlay_compositor_dispose; + object_class->finalize = gst_d3d11_overlay_compositor_finalize; } static void gst_d3d11_overlay_compositor_init (GstD3D11OverlayCompositor * self) { - self->priv = (GstD3D11OverlayCompositorPrivate *) - gst_d3d11_overlay_compositor_get_instance_private (self); + self->priv = new GstD3D11OverlayCompositorPrivate (); } static void -gst_d3d11_overlay_compositor_dispose (GObject * object) +gst_d3d11_overlay_compositor_finalize (GObject * object) { GstD3D11OverlayCompositor *self = GST_D3D11_OVERLAY_COMPOSITOR (object); - GstD3D11OverlayCompositorPrivate *priv = self->priv; - gst_d3d11_overlay_compositor_free_overlays (self); - - GST_D3D11_CLEAR_COM (priv->ps); - GST_D3D11_CLEAR_COM (priv->premul_ps); - GST_D3D11_CLEAR_COM (priv->vs); - GST_D3D11_CLEAR_COM (priv->layout); - GST_D3D11_CLEAR_COM (priv->sampler); - GST_D3D11_CLEAR_COM (priv->blend); - GST_D3D11_CLEAR_COM (priv->index_buffer); + delete self->priv; gst_clear_object (&self->device); - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } -static GstD3D11CompositionOverlay * +static GstD3D11CompositionOverlayPtr gst_d3d11_composition_overlay_new (GstD3D11OverlayCompositor * self, GstVideoOverlayRectangle * overlay_rect) { GstD3D11OverlayCompositorPrivate *priv = self->priv; - GstD3D11CompositionOverlay *overlay = nullptr; gint x, y; guint width, height; D3D11_SUBRESOURCE_DATA subresource_data; @@ -343,32 +340,16 @@ gst_d3d11_composition_overlay_new (GstD3D11OverlayCompositor * self, context_handle->Unmap (vertex_buffer.Get (), 0); - overlay = g_new0 (GstD3D11CompositionOverlay, 1); + auto overlay = std::make_shared < GstD3D11CompositionOverlay > (); overlay->overlay_rect = gst_video_overlay_rectangle_ref (overlay_rect); - overlay->texture = texture.Detach (); - overlay->srv = srv.Detach (); - overlay->vertex_buffer = vertex_buffer.Detach (); + overlay->texture = texture; + overlay->srv = srv; + overlay->vertex_buffer = vertex_buffer; overlay->premul_alpha = premul_alpha; return overlay; } -static void -gst_d3d11_composition_overlay_free (GstD3D11CompositionOverlay * overlay) -{ - if (!overlay) - return; - - if (overlay->overlay_rect) - gst_video_overlay_rectangle_unref (overlay->overlay_rect); - - GST_D3D11_CLEAR_COM (overlay->srv); - GST_D3D11_CLEAR_COM (overlay->texture); - GST_D3D11_CLEAR_COM (overlay->vertex_buffer); - - g_free (overlay); -} - static gboolean gst_d3d11_overlay_compositor_setup_shader (GstD3D11OverlayCompositor * self) { @@ -550,39 +531,27 @@ gst_d3d11_overlay_compositor_new (GstD3D11Device * device, return self; } -static void -gst_d3d11_overlay_compositor_free_overlays (GstD3D11OverlayCompositor * self) -{ - GstD3D11OverlayCompositorPrivate *priv = self->priv; - - if (priv->overlays) { - g_list_free_full (priv->overlays, - (GDestroyNotify) gst_d3d11_composition_overlay_free); - - priv->overlays = nullptr; - } -} - -static gint -find_in_compositor (const GstD3D11CompositionOverlay * overlay, - const GstVideoOverlayRectangle * rect) -{ - return !(overlay->overlay_rect == rect); -} - static gboolean -is_in_video_overlay_composition (GstVideoOverlayComposition * voc, - GstD3D11CompositionOverlay * overlay) +gst_d3d11_overlay_compositor_foreach_meta (GstBuffer * buffer, GstMeta ** meta, + std::vector < GstVideoOverlayRectangle * >*overlay_rect) { - guint i; + GstVideoOverlayCompositionMeta *cmeta; + guint num_rect; - for (i = 0; i < gst_video_overlay_composition_n_rectangles (voc); i++) { - GstVideoOverlayRectangle *rectangle = - gst_video_overlay_composition_get_rectangle (voc, i); - if (overlay->overlay_rect == rectangle) - return TRUE; + if ((*meta)->info->api != GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE) + return TRUE; + + cmeta = (GstVideoOverlayCompositionMeta *) (*meta); + if (!cmeta->overlay) + return TRUE; + + num_rect = gst_video_overlay_composition_n_rectangles (cmeta->overlay); + for (guint i = 0; i < num_rect; i++) { + auto rect = gst_video_overlay_composition_get_rectangle (cmeta->overlay, i); + overlay_rect->push_back (rect); } - return FALSE; + + return TRUE; } gboolean @@ -590,61 +559,64 @@ gst_d3d11_overlay_compositor_upload (GstD3D11OverlayCompositor * compositor, GstBuffer * buf) { GstD3D11OverlayCompositorPrivate *priv; - GstVideoOverlayCompositionMeta *meta; - gint i, num_overlays; - GList *iter; + std::vector < GstVideoOverlayRectangle * >new_overlay_rect; g_return_val_if_fail (compositor != nullptr, FALSE); g_return_val_if_fail (GST_IS_BUFFER (buf), FALSE); priv = compositor->priv; - meta = gst_buffer_get_video_overlay_composition_meta (buf); - if (!meta) { - gst_d3d11_overlay_compositor_free_overlays (compositor); + gst_buffer_foreach_meta (buf, + (GstBufferForeachMetaFunc) gst_d3d11_overlay_compositor_foreach_meta, + &new_overlay_rect); + + if (new_overlay_rect.empty ()) { + priv->overlays.clear (); return TRUE; } - num_overlays = gst_video_overlay_composition_n_rectangles (meta->overlay); - if (!num_overlays) { - gst_d3d11_overlay_compositor_free_overlays (compositor); - return TRUE; - } + GST_LOG_OBJECT (compositor, "Found %" G_GSIZE_FORMAT + " overlay rectangles, %" G_GSIZE_FORMAT " in current queue", + new_overlay_rect.size (), priv->overlays.size ()); - GST_LOG_OBJECT (compositor, "Upload %d overlay rectangles", num_overlays); - - /* Upload new overlay */ - for (i = 0; i < num_overlays; i++) { - GstVideoOverlayRectangle *rectangle = - gst_video_overlay_composition_get_rectangle (meta->overlay, i); - - if (!g_list_find_custom (priv->overlays, - rectangle, (GCompareFunc) find_in_compositor)) { - GstD3D11CompositionOverlay *overlay = nullptr; - - overlay = gst_d3d11_composition_overlay_new (compositor, rectangle); - - if (!overlay) + /* *INDENT-OFF* */ + for (auto it : new_overlay_rect) { + if (std::find_if (priv->overlays.begin (), priv->overlays.end (), + [&] (const auto & overlay) -> bool { + return overlay->overlay_rect == it; + }) == priv->overlays.end ()) { + auto new_overlay = gst_d3d11_composition_overlay_new (compositor, it); + if (!new_overlay) return FALSE; - priv->overlays = g_list_append (priv->overlays, overlay); + priv->overlays.push_back (new_overlay); } } + /* *INDENT-ON* */ + + GST_LOG_OBJECT (compositor, "Overlay rectangles in queue after uploaded %" + G_GSIZE_FORMAT, priv->overlays.size ()); /* Remove old overlay */ - iter = priv->overlays; - while (iter) { - GstD3D11CompositionOverlay *overlay = - (GstD3D11CompositionOverlay *) iter->data; - GList *next = iter->next; - - if (!is_in_video_overlay_composition (meta->overlay, overlay)) { - priv->overlays = g_list_delete_link (priv->overlays, iter); - gst_d3d11_composition_overlay_free (overlay); + /* *INDENT-OFF* */ + auto it = priv->overlays.begin (); + while (it != priv->overlays.end ()) { + auto old_overlay = *it; + if (std::find_if (new_overlay_rect.begin (), new_overlay_rect.end (), + [&] (const auto & overlay) -> bool { + return overlay == old_overlay->overlay_rect; + }) == new_overlay_rect.end ()) { + GST_LOG_OBJECT (compositor, "Removing %p from queue", + old_overlay->overlay_rect); + it = priv->overlays.erase (it); + } else { + it++; } - - iter = next; } + /* *INDENT-ON* */ + + GST_LOG_OBJECT (compositor, "Final queue size %" G_GSIZE_FORMAT, + priv->overlays.size ()); return TRUE; } @@ -677,45 +649,49 @@ gst_d3d11_overlay_compositor_draw_unlocked (GstD3D11OverlayCompositor * compositor, ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES]) { GstD3D11OverlayCompositorPrivate *priv; - GList *iter; ID3D11DeviceContext *context; ID3D11ShaderResourceView *clear_view[GST_VIDEO_MAX_PLANES] = { nullptr, }; UINT strides = sizeof (VertexData); UINT offsets = 0; + ID3D11SamplerState *samplers[1]; g_return_val_if_fail (compositor != nullptr, FALSE); g_return_val_if_fail (rtv != nullptr, FALSE); priv = compositor->priv; - if (!priv->overlays) + if (priv->overlays.empty ()) return TRUE; + samplers[0] = priv->sampler.Get (); + context = gst_d3d11_device_get_device_context_handle (compositor->device); context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout (priv->layout); - context->IASetIndexBuffer (priv->index_buffer, DXGI_FORMAT_R16_UINT, 0); - context->PSSetSamplers (0, 1, &priv->sampler); - context->VSSetShader (priv->vs, nullptr, 0); + context->IASetInputLayout (priv->layout.Get ()); + context->IASetIndexBuffer (priv->index_buffer.Get (), + DXGI_FORMAT_R16_UINT, 0); + context->PSSetSamplers (0, 1, samplers); + context->VSSetShader (priv->vs.Get (), nullptr, 0); context->RSSetViewports (1, &priv->viewport); context->OMSetRenderTargets (1, rtv, nullptr); - context->OMSetBlendState (priv->blend, nullptr, 0xffffffff); + context->OMSetBlendState (priv->blend.Get (), nullptr, 0xffffffff); - for (iter = priv->overlays; iter; iter = g_list_next (iter)) { - GstD3D11CompositionOverlay *overlay = - (GstD3D11CompositionOverlay *) iter->data; + /* *INDENT-OFF* */ + for (auto overlay : priv->overlays) { + ID3D11ShaderResourceView *srv[] = { overlay->srv.Get () }; + ID3D11Buffer *vertex_buf[] = { overlay->vertex_buffer.Get () }; if (overlay->premul_alpha) - context->PSSetShader (priv->premul_ps, nullptr, 0); + context->PSSetShader (priv->premul_ps.Get (), nullptr, 0); else - context->PSSetShader (priv->ps, nullptr, 0); + context->PSSetShader (priv->ps.Get (), nullptr, 0); - context->PSSetShaderResources (0, 1, &overlay->srv); - context->IASetVertexBuffers (0, - 1, &overlay->vertex_buffer, &strides, &offsets); + context->PSSetShaderResources (0, 1, srv); + context->IASetVertexBuffers (0, 1, vertex_buf, &strides, &offsets); context->DrawIndexed (6, 0, 0); } + /* *INDENT-ON* */ context->PSSetShaderResources (0, 1, clear_view); context->OMSetRenderTargets (0, nullptr, nullptr); diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp index 7a1713fcb1..57cc2ffd01 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp @@ -1358,6 +1358,27 @@ gst_d3d11_video_sink_check_device_update (GstD3D11VideoSink * self, self->device = (GstD3D11Device *) gst_object_ref (dmem->device); } +static gboolean +gst_d3d11_video_sink_foreach_meta (GstBuffer * buffer, GstMeta ** meta, + GstBuffer * uploaded) +{ + GstVideoOverlayCompositionMeta *cmeta; + + if ((*meta)->info->api != GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE) + return TRUE; + + cmeta = (GstVideoOverlayCompositionMeta *) (*meta); + if (!cmeta->overlay) + return TRUE; + + if (gst_video_overlay_composition_n_rectangles (cmeta->overlay) == 0) + return TRUE; + + gst_buffer_add_video_overlay_composition_meta (uploaded, cmeta->overlay); + + return TRUE; +} + static GstFlowReturn gst_d3d11_video_sink_prepare (GstBaseSink * sink, GstBuffer * buffer) { @@ -1382,8 +1403,6 @@ gst_d3d11_video_sink_prepare (GstBaseSink * sink, GstBuffer * buffer) } if (!gst_is_d3d11_buffer (buffer)) { - GstVideoOverlayCompositionMeta *overlay_meta; - ret = gst_buffer_pool_acquire_buffer (self->pool, &self->prepared_buffer, nullptr); if (ret != GST_FLOW_OK) @@ -1404,11 +1423,9 @@ gst_d3d11_video_sink_prepare (GstBaseSink * sink, GstBuffer * buffer) gst_memory_unmap (mem, &info); } - overlay_meta = gst_buffer_get_video_overlay_composition_meta (buffer); - if (overlay_meta) { - gst_buffer_add_video_overlay_composition_meta (self->prepared_buffer, - overlay_meta->overlay); - } + gst_buffer_foreach_meta (buffer, + (GstBufferForeachMetaFunc) gst_d3d11_video_sink_foreach_meta, + self->prepared_buffer); } else { self->prepared_buffer = gst_buffer_ref (buffer); }