mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
d3d11videosink: Add a property to support rendering statistics data on window
Add a new property "render-stats" to allow rendering statistics data on window for debugging and/or development purpose. Text rendering will be accelerated by GPU since this implementation uses Direct2D/DirectWrite API and Direct3D inter-op for minimal overhead. Specifically, text data will be rendered on swapchain backbuffer directly without any copy/allocation of extra texture. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1830>
This commit is contained in:
parent
22990bb9ea
commit
96831233a3
5 changed files with 352 additions and 15 deletions
|
@ -44,6 +44,7 @@ enum
|
|||
PROP_ENABLE_NAVIGATION_EVENTS,
|
||||
PROP_FULLSCREEN_TOGGLE_MODE,
|
||||
PROP_FULLSCREEN,
|
||||
PROP_RENDER_STATS,
|
||||
};
|
||||
|
||||
#define DEFAULT_ADAPTER -1
|
||||
|
@ -51,6 +52,7 @@ enum
|
|||
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
||||
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
||||
#define DEFAULT_FULLSCREEN FALSE
|
||||
#define DEFAULT_RENDER_STATS FALSE
|
||||
|
||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
|
@ -84,6 +86,7 @@ struct _GstD3D11VideoSink
|
|||
gboolean enable_navigation_events;
|
||||
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
||||
gboolean fullscreen;
|
||||
gboolean render_stats;
|
||||
|
||||
/* saved render rectangle until we have a window */
|
||||
GstVideoRectangle render_rect;
|
||||
|
@ -178,6 +181,16 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass)
|
|||
"Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
|
||||
DEFAULT_FULLSCREEN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
|
||||
g_param_spec_boolean ("render-stats",
|
||||
"Render Stats",
|
||||
"Render statistics data (e.g., average framerate) on window",
|
||||
DEFAULT_RENDER_STATS,
|
||||
GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
#endif
|
||||
|
||||
element_class->set_context =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_set_context);
|
||||
|
||||
|
@ -213,6 +226,7 @@ gst_d3d11_video_sink_init (GstD3D11VideoSink * self)
|
|||
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
|
||||
self->fullscreen_toggle_mode = DEFAULT_FULLSCREEN_TOGGLE_MODE;
|
||||
self->fullscreen = DEFAULT_FULLSCREEN;
|
||||
self->render_stats = DEFAULT_RENDER_STATS;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -252,6 +266,11 @@ gst_d3d11_videosink_set_property (GObject * object, guint prop_id,
|
|||
g_object_set (self->window, "fullscreen", self->fullscreen, NULL);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
case PROP_RENDER_STATS:
|
||||
self->render_stats = g_value_get_boolean (value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -285,6 +304,11 @@ gst_d3d11_videosink_get_property (GObject * object, guint prop_id,
|
|||
g_value_set_boolean (value, self->fullscreen);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
case PROP_RENDER_STATS:
|
||||
g_value_set_boolean (value, self->render_stats);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -592,6 +616,9 @@ gst_d3d11_video_sink_start (GstBaseSink * sink)
|
|||
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
|
||||
"fullscreen", self->fullscreen,
|
||||
"enable-navigation-events", self->enable_navigation_events, NULL);
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
g_object_set (self->window, "render-stats", self->render_stats, NULL);
|
||||
#endif
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
g_signal_connect (self->window, "key-event",
|
||||
|
@ -864,6 +891,7 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
|||
gboolean need_unref = FALSE;
|
||||
gboolean do_device_copy = TRUE;
|
||||
gint i;
|
||||
GstStructure *stats = NULL;
|
||||
|
||||
render_buf = buf;
|
||||
|
||||
|
@ -955,7 +983,10 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
|||
rect.w = self->video_width;
|
||||
rect.h = self->video_height;
|
||||
|
||||
ret = gst_d3d11_window_render (self->window, render_buf, &rect);
|
||||
if (self->render_stats)
|
||||
stats = gst_base_sink_get_stats (GST_BASE_SINK_CAST (self));
|
||||
|
||||
ret = gst_d3d11_window_render (self->window, render_buf, &rect, stats);
|
||||
if (need_unref)
|
||||
gst_buffer_unref (render_buf);
|
||||
|
||||
|
@ -1013,7 +1044,7 @@ gst_d3d11_video_sink_expose (GstVideoOverlay * overlay)
|
|||
rect.w = GST_VIDEO_SINK_WIDTH (self);
|
||||
rect.h = GST_VIDEO_SINK_HEIGHT (self);
|
||||
|
||||
gst_d3d11_window_render (self->window, NULL, &rect);
|
||||
gst_d3d11_window_render (self->window, NULL, &rect, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ enum
|
|||
PROP_ENABLE_NAVIGATION_EVENTS,
|
||||
PROP_FULLSCREEN_TOGGLE_MODE,
|
||||
PROP_FULLSCREEN,
|
||||
PROP_RENDER_STATS,
|
||||
};
|
||||
|
||||
/* basesink */
|
||||
|
@ -85,6 +86,7 @@ enum
|
|||
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
||||
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
||||
#define DEFAULT_FULLSCREEN FALSE
|
||||
#define DEFAULT_RENDER_STATS FALSE
|
||||
|
||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
|
@ -238,6 +240,15 @@ gst_d3d11_video_sink_bin_class_init (GstD3D11VideoSinkBinClass * klass)
|
|||
"fullscreen",
|
||||
"Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
|
||||
DEFAULT_FULLSCREEN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
|
||||
g_param_spec_boolean ("render-stats",
|
||||
"Render Stats",
|
||||
"Render statistics data (e.g., average framerate) on window",
|
||||
DEFAULT_RENDER_STATS,
|
||||
GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
#endif
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"Direct3D11 video sink bin", "Sink/Video",
|
||||
|
|
|
@ -34,9 +34,17 @@
|
|||
#endif
|
||||
#include <windows.ui.xaml.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
#include <dwrite.h>
|
||||
#include <d2d1_1.h>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP || defined(HAVE_DIRECT_WRITE)
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
#endif
|
||||
|
||||
|
@ -45,6 +53,21 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
|
|||
#define GST_CAT_DEFAULT gst_d3d11_window_debug
|
||||
}
|
||||
|
||||
struct _GstD3D11WindowPrivate
|
||||
{
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
IDWriteFactory *dwrite_factory;
|
||||
IDWriteTextFormat *dwrite_format;
|
||||
|
||||
ID2D1Factory1 *d2d_factory;
|
||||
ID2D1Device *d2d_device;
|
||||
ID2D1DeviceContext *d2d_device_context;
|
||||
ID2D1SolidColorBrush *d2d_brush;
|
||||
#else
|
||||
gpointer dummy;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -54,12 +77,14 @@ enum
|
|||
PROP_FULLSCREEN_TOGGLE_MODE,
|
||||
PROP_FULLSCREEN,
|
||||
PROP_WINDOW_HANDLE,
|
||||
PROP_RENDER_STATS,
|
||||
};
|
||||
|
||||
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
||||
#define DEFAULT_FULLSCREEN FALSE
|
||||
#define DEFAULT_RENDER_STATS FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -94,7 +119,8 @@ gst_d3d11_window_fullscreen_toggle_mode_type (void)
|
|||
}
|
||||
|
||||
#define gst_d3d11_window_parent_class parent_class
|
||||
G_DEFINE_ABSTRACT_TYPE (GstD3D11Window, gst_d3d11_window, GST_TYPE_OBJECT);
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstD3D11Window, gst_d3d11_window,
|
||||
GST_TYPE_OBJECT);
|
||||
|
||||
static void gst_d3d11_window_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
|
@ -102,7 +128,7 @@ static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
|||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_d3d11_window_dispose (GObject * object);
|
||||
static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
|
||||
GstBuffer * buffer);
|
||||
GstBuffer * buffer, GstStructure * stats);
|
||||
static void gst_d3d11_window_on_resize_default (GstD3D11Window * window,
|
||||
guint width, guint height);
|
||||
|
||||
|
@ -158,6 +184,15 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
|
|||
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
|
||||
g_param_spec_boolean ("render-stats",
|
||||
"Render Stats",
|
||||
"Render statistics data (e.g., average framerate) on window",
|
||||
DEFAULT_RENDER_STATS,
|
||||
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
|
||||
#endif
|
||||
|
||||
d3d11_window_signals[SIGNAL_KEY_EVENT] =
|
||||
g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
|
@ -176,6 +211,10 @@ gst_d3d11_window_init (GstD3D11Window * self)
|
|||
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
|
||||
self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
|
||||
self->fullscreen = DEFAULT_FULLSCREEN;
|
||||
self->render_stats = DEFAULT_RENDER_STATS;
|
||||
|
||||
self->priv =
|
||||
(GstD3D11WindowPrivate *) gst_d3d11_window_get_instance_private (self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -213,6 +252,11 @@ gst_d3d11_window_set_property (GObject * object, guint prop_id,
|
|||
case PROP_WINDOW_HANDLE:
|
||||
self->external_handle = (guintptr) g_value_get_pointer (value);
|
||||
break;
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
case PROP_RENDER_STATS:
|
||||
self->render_stats = g_value_get_boolean (value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -244,10 +288,155 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
static void
|
||||
gst_d3d11_window_release_dwrite_resources (GstD3D11Window * self)
|
||||
{
|
||||
GstD3D11WindowPrivate *priv = self->priv;
|
||||
|
||||
if (priv->d2d_device_context) {
|
||||
priv->d2d_device_context->Release ();
|
||||
priv->d2d_device_context = NULL;
|
||||
}
|
||||
|
||||
if (priv->d2d_factory) {
|
||||
priv->d2d_factory->Release ();
|
||||
priv->d2d_factory = NULL;
|
||||
}
|
||||
|
||||
if (priv->d2d_device) {
|
||||
priv->d2d_device->Release ();
|
||||
priv->d2d_device = NULL;
|
||||
}
|
||||
|
||||
if (priv->d2d_brush) {
|
||||
priv->d2d_brush->Release ();
|
||||
priv->d2d_brush = NULL;
|
||||
}
|
||||
|
||||
if (priv->dwrite_factory) {
|
||||
priv->dwrite_factory->Release ();
|
||||
priv->dwrite_factory = NULL;
|
||||
}
|
||||
|
||||
if (priv->dwrite_format) {
|
||||
priv->dwrite_format->Release ();
|
||||
priv->dwrite_format = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_prepare_dwrite_device (GstD3D11Window * self)
|
||||
{
|
||||
GstD3D11WindowPrivate *priv = self->priv;
|
||||
HRESULT hr;
|
||||
ComPtr<IDXGIDevice> dxgi_device;
|
||||
ID3D11Device *device_handle;
|
||||
|
||||
if (!self->device) {
|
||||
GST_ERROR_OBJECT (self, "D3D11Device is unavailable");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Already prepared */
|
||||
if (priv->d2d_device)
|
||||
return;
|
||||
|
||||
hr = D2D1CreateFactory (D2D1_FACTORY_TYPE_MULTI_THREADED,
|
||||
IID_PPV_ARGS (&priv->d2d_factory));
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
device_handle = gst_d3d11_device_get_device_handle (self->device);
|
||||
hr = device_handle->QueryInterface (IID_PPV_ARGS (&dxgi_device));
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
hr = priv->d2d_factory->CreateDevice (dxgi_device.Get (), &priv->d2d_device);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
hr = priv->d2d_device->CreateDeviceContext (D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
|
||||
&priv->d2d_device_context);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
hr = priv->d2d_device_context->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Yellow),
|
||||
&priv->d2d_brush);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof (IDWriteFactory), (IUnknown **) &priv->dwrite_factory);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
/* Configure font */
|
||||
hr = priv->dwrite_factory->CreateTextFormat(L"Arial", NULL,
|
||||
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-US", &priv->dwrite_format);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Direct2D device is prepared");
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
gst_d3d11_window_release_dwrite_resources (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dwrite_on_resize (GstD3D11Window * self,
|
||||
ID3D11Texture2D * backbuffer)
|
||||
{
|
||||
GstD3D11WindowPrivate *priv = self->priv;
|
||||
ComPtr<IDXGISurface> dxgi_surface;
|
||||
ComPtr<ID2D1Bitmap1> bitmap;
|
||||
D2D1_BITMAP_PROPERTIES1 prop;
|
||||
HRESULT hr;
|
||||
|
||||
if (!priv->d2d_device)
|
||||
return;
|
||||
|
||||
prop.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
|
||||
/* default dpi */
|
||||
prop.dpiX = 96.0f;
|
||||
prop.dpiY = 96.0f;
|
||||
prop.bitmapOptions =
|
||||
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
|
||||
prop.colorContext = NULL;
|
||||
|
||||
hr = backbuffer->QueryInterface (IID_PPV_ARGS (&dxgi_surface));
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
hr = priv->d2d_device_context->CreateBitmapFromDxgiSurface (dxgi_surface.Get (),
|
||||
&prop, &bitmap);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
goto error;
|
||||
|
||||
priv->d2d_device_context->SetTarget (bitmap.Get ());
|
||||
|
||||
GST_LOG_OBJECT (self, "New D2D bitmap has been configured");
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
gst_d3d11_window_release_dwrite_resources (self);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
gst_d3d11_window_release_resources (GstD3D11Device * device,
|
||||
GstD3D11Window * window)
|
||||
{
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
gst_d3d11_window_release_dwrite_resources (window);
|
||||
#endif
|
||||
|
||||
if (window->rtv) {
|
||||
window->rtv->Release ();
|
||||
window->rtv = NULL;
|
||||
|
@ -287,6 +476,9 @@ static void
|
|||
gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
|
||||
guint height)
|
||||
{
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
GstD3D11WindowPrivate *priv = window->priv;
|
||||
#endif
|
||||
HRESULT hr;
|
||||
ID3D11Device *device_handle;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
@ -312,6 +504,12 @@ gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
|
|||
window->pov = NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
/* D2D bitmap need to be cleared before resizing swapchain buffer */
|
||||
if (priv->d2d_device_context)
|
||||
priv->d2d_device_context->SetTarget (NULL);
|
||||
#endif
|
||||
|
||||
swap_chain->GetDesc (&swap_desc);
|
||||
hr = swap_chain->ResizeBuffers (0, width, height, window->dxgi_format,
|
||||
swap_desc.Flags);
|
||||
|
@ -378,10 +576,15 @@ gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
|
|||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
if (window->render_stats)
|
||||
gst_d3d11_window_dwrite_on_resize (window, backbuffer);
|
||||
#endif
|
||||
|
||||
window->first_present = TRUE;
|
||||
|
||||
/* redraw the last scene if cached buffer exits */
|
||||
gst_d3d111_window_present (window, NULL);
|
||||
gst_d3d111_window_present (window, NULL, NULL);
|
||||
|
||||
done:
|
||||
if (backbuffer)
|
||||
|
@ -489,14 +692,23 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
|
||||
if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
|
||||
if (formats[2].supported) {
|
||||
chosen_format = &formats[2];
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
if (window->render_stats && formats[1].supported) {
|
||||
/* FIXME: D2D seems to be accepting only DXGI_FORMAT_B8G8R8A8_UNORM */
|
||||
chosen_format = &formats[1];
|
||||
} else
|
||||
#else
|
||||
{
|
||||
for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
|
||||
if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
|
||||
if (formats[2].supported) {
|
||||
chosen_format = &formats[2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!chosen_format) {
|
||||
/* prefer native format over conversion */
|
||||
|
@ -745,6 +957,11 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
|
|||
"Cannot create overlay compositor");
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
if (window->render_stats)
|
||||
gst_d3d11_window_prepare_dwrite_device (window);
|
||||
#endif
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
||||
/* call resize to allocated resources */
|
||||
|
@ -815,8 +1032,60 @@ gst_d3d11_window_buffer_ensure_processor_input (GstD3D11Window * self,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIRECT_WRITE
|
||||
static void
|
||||
gst_d3d11_window_present_d2d (GstD3D11Window * self, GstStructure * stats)
|
||||
{
|
||||
GstD3D11WindowPrivate *priv = self->priv;
|
||||
HRESULT hr;
|
||||
gdouble framerate = 0.0;
|
||||
guint64 dropped = 0;
|
||||
guint64 rendered = 0;
|
||||
std::wostringstream stats_str;
|
||||
ComPtr<IDWriteTextLayout> layout;
|
||||
FLOAT left;
|
||||
FLOAT top;
|
||||
|
||||
if (!priv->d2d_device)
|
||||
return;
|
||||
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
gst_structure_get_double (stats, "average-rate", &framerate);
|
||||
gst_structure_get_uint64 (stats, "dropped", &dropped);
|
||||
gst_structure_get_uint64 (stats, "rendered", &rendered);
|
||||
|
||||
stats_str.precision (5);
|
||||
stats_str << "Average-rate: " << framerate << std::endl;
|
||||
stats_str << "Dropped: " << dropped << std::endl;
|
||||
stats_str << "Rendered: " << rendered << std::endl;
|
||||
|
||||
hr = priv->dwrite_factory->CreateTextLayout (stats_str.str().c_str(),
|
||||
(UINT32) stats_str.str().size(), priv->dwrite_format,
|
||||
self->render_rect.right - self->render_rect.left,
|
||||
self->render_rect.bottom - self->render_rect.top,
|
||||
&layout);
|
||||
if (!gst_d3d11_result (hr, self->device))
|
||||
return;
|
||||
|
||||
left = self->render_rect.left + 5.0f;
|
||||
top = self->render_rect.top + 5.0f;
|
||||
|
||||
priv->d2d_device_context->BeginDraw ();
|
||||
priv->d2d_device_context->DrawTextLayout(D2D1::Point2F(left, top),
|
||||
layout.Get(), priv->d2d_brush);
|
||||
|
||||
hr = priv->d2d_device_context->EndDraw ();
|
||||
gst_d3d11_result (hr, self->device);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
|
||||
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
|
||||
GstStructure * stats)
|
||||
{
|
||||
GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (self);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
@ -885,6 +1154,10 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_DIRECT_WRITE
|
||||
gst_d3d11_window_present_d2d (self, stats);
|
||||
#endif
|
||||
|
||||
ret = klass->present (self, present_flags);
|
||||
|
||||
self->first_present = FALSE;
|
||||
|
@ -895,7 +1168,7 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
|
|||
|
||||
GstFlowReturn
|
||||
gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
|
||||
GstVideoRectangle * rect)
|
||||
GstVideoRectangle * rect, GstStructure * stats)
|
||||
{
|
||||
GstMemory *mem;
|
||||
GstFlowReturn ret;
|
||||
|
@ -907,13 +1180,19 @@ gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
|
|||
if (!gst_is_d3d11_memory (mem)) {
|
||||
GST_ERROR_OBJECT (window, "Invalid buffer");
|
||||
|
||||
if (stats)
|
||||
gst_structure_free (stats);
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
ret = gst_d3d111_window_present (window, buffer);
|
||||
ret = gst_d3d111_window_present (window, buffer, stats);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
||||
if (stats)
|
||||
gst_structure_free (stats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ G_BEGIN_DECLS
|
|||
|
||||
typedef struct _GstD3D11Window GstD3D11Window;
|
||||
typedef struct _GstD3D11WindowClass GstD3D11WindowClass;
|
||||
typedef struct _GstD3D11WindowPrivate GstD3D11WindowPrivate;
|
||||
|
||||
#define GST_D3D11_WINDOW_FLOW_CLOSED GST_FLOW_CUSTOM_ERROR
|
||||
|
||||
|
@ -76,6 +77,7 @@ struct _GstD3D11Window
|
|||
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
||||
gboolean requested_fullscreen;
|
||||
gboolean fullscreen;
|
||||
gboolean render_stats;
|
||||
|
||||
GstVideoInfo info;
|
||||
GstVideoInfo render_info;
|
||||
|
@ -103,6 +105,8 @@ struct _GstD3D11Window
|
|||
GstBuffer *cached_buffer;
|
||||
gboolean first_present;
|
||||
gboolean allow_tearing;
|
||||
|
||||
GstD3D11WindowPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstD3D11WindowClass
|
||||
|
@ -153,7 +157,8 @@ gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
|
|||
|
||||
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
|
||||
GstBuffer * buffer,
|
||||
GstVideoRectangle * src_rect);
|
||||
GstVideoRectangle * src_rect,
|
||||
GstStructure * stats);
|
||||
|
||||
gboolean gst_d3d11_window_unlock (GstD3D11Window * window);
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ d3d11_lib = cc.find_library('d3d11', required : d3d11_option)
|
|||
dxgi_lib = cc.find_library('dxgi', required : d3d11_option)
|
||||
d3dcompiler_lib = cc.find_library('d3dcompiler', required: d3d11_option)
|
||||
runtimeobject_lib = cc.find_library('runtimeobject', required : false)
|
||||
dwrite_lib = cc.find_library('dwrite', required : false)
|
||||
d2d1_lib = cc.find_library('d2d1', required : false)
|
||||
|
||||
foreach dxgi_h: dxgi_headers
|
||||
if not have_dxgi_header and cc.has_header(dxgi_h[0])
|
||||
|
@ -177,6 +179,15 @@ if get_option('debug') and not (winapi_app_only and get_option('b_vscrt') == 'md
|
|||
set_variable(f.get(3), true)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# Maybe we want to implement DirectWrite based text rendering in the future,
|
||||
# but currently only debugging purpose.
|
||||
# Also, MinGW is not supported for now because of toolchain issue
|
||||
if cc.get_id() == 'msvc' and dwrite_lib.found() and d2d1_lib.found() and cc.has_header('dwrite.h') and cc.has_header('d2d1_1.h')
|
||||
d3d11_conf.set('HAVE_DIRECT_WRITE', 1)
|
||||
extra_dep += [dwrite_lib, d2d1_lib]
|
||||
message('Enable DirectWrite support in D3D11 plugin')
|
||||
endif
|
||||
else
|
||||
message('Disable D3D11Debug and DXGIDebug layers')
|
||||
endif
|
||||
|
|
Loading…
Reference in a new issue