return TRUE;
}
-static gboolean
+static GstFlowReturn
gst_d3d11_video_sink_update_window (GstD3D11VideoSink * self, GstCaps * caps)
{
gint video_width, video_height;
guint num, den;
GError *error = NULL;
GstStructure *config;
+ GstD3D11Window *window;
+ GstFlowReturn ret = GST_FLOW_OK;
GST_DEBUG_OBJECT (self, "Updating window with caps %" GST_PTR_FORMAT, caps);
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, (nullptr),
("Failed to open window."));
- return FALSE;
+ return GST_FLOW_ERROR;
}
if (!gst_video_info_from_caps (&self->info, caps)) {
GST_DEBUG_OBJECT (self,
"Could not locate image format from caps %" GST_PTR_FORMAT, caps);
LeaveCriticalSection (&self->lock);
- return FALSE;
+ return GST_FLOW_ERROR;
}
video_width = GST_VIDEO_INFO_WIDTH (&self->info);
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (nullptr),
("Error calculating the output display ratio of the video."));
- return FALSE;
+ return GST_FLOW_ERROR;
}
GST_DEBUG_OBJECT (self,
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (nullptr),
("Error calculating the output display ratio of the video."));
- return FALSE;
+ return GST_FLOW_ERROR;
}
if (self->pending_render_rect) {
GST_D3D11_CONVERTER_OPT_PRIMARIES_MODE,
GST_TYPE_VIDEO_PRIMARIES_MODE, self->primaries_mode, nullptr);
- if (!gst_d3d11_window_prepare (self->window, GST_VIDEO_SINK_WIDTH (self),
- GST_VIDEO_SINK_HEIGHT (self), caps, config, self->display_format,
- &error)) {
+ window = (GstD3D11Window *) gst_object_ref (self->window);
+ LeaveCriticalSection (&self->lock);
+
+ ret = gst_d3d11_window_prepare (window, GST_VIDEO_SINK_WIDTH (self),
+ GST_VIDEO_SINK_HEIGHT (self), caps, config, self->display_format, &error);
+ if (ret != GST_FLOW_OK) {
GstMessage *error_msg;
- LeaveCriticalSection (&self->lock);
+ if (ret == GST_FLOW_FLUSHING) {
+ GstD3D11CSLockGuard lk (&self->lock);
+ GST_WARNING_OBJECT (self, "Couldn't prepare window but we are flushing");
+ gst_clear_object (&self->window);
+ gst_object_unref (window);
+
+ return GST_FLOW_FLUSHING;
+ }
GST_ERROR_OBJECT (self, "cannot create swapchain");
error_msg = gst_message_new_error (GST_OBJECT_CAST (self),
error, "Failed to prepare d3d11window");
g_clear_error (&error);
gst_element_post_message (GST_ELEMENT (self), error_msg);
+ gst_object_unref (window);
- return FALSE;
+ return GST_FLOW_ERROR;
}
if (self->title) {
- gst_d3d11_window_set_title (self->window, self->title);
+ gst_d3d11_window_set_title (window, self->title);
g_clear_pointer (&self->title, g_free);
}
- LeaveCriticalSection (&self->lock);
+ gst_object_unref (window);
- return TRUE;
+ return GST_FLOW_OK;
}
static void
g_signal_connect (self->window, "present",
G_CALLBACK (gst_d3d11_video_sink_present), self);
+ GST_DEBUG_OBJECT (self,
+ "Have prepared window %" GST_PTR_FORMAT, self->window);
+
return TRUE;
}
if (self->caps_updated || !self->window) {
GstCaps *caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (sink));
- gboolean update_ret;
/* shouldn't happen */
if (!caps)
return GST_FLOW_NOT_NEGOTIATED;
- update_ret = gst_d3d11_video_sink_update_window (self, caps);
+ ret = gst_d3d11_video_sink_update_window (self, caps);
gst_caps_unref (caps);
- if (!update_ret)
- return GST_FLOW_NOT_NEGOTIATED;
+ if (ret != GST_FLOW_OK)
+ return ret;
}
gst_d3d11_window_show (self->window);
GstBuffer * buffer, GstBuffer * render_target);
static void gst_d3d11_window_on_resize_default (GstD3D11Window * window,
guint width, guint height);
-static gboolean gst_d3d11_window_prepare_default (GstD3D11Window * window,
+static GstFlowReturn gst_d3d11_window_prepare_default (GstD3D11Window * window,
guint display_width, guint display_height, GstCaps * caps,
GstStructure * config, DXGI_FORMAT display_format, GError ** error);
gboolean supported;
} GstD3D11WindowDisplayFormat;
-gboolean
+GstFlowReturn
gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
guint display_height, GstCaps * caps, GstStructure * config,
DXGI_FORMAT display_format, GError ** error)
{
GstD3D11WindowClass *klass;
- g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
+ g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
klass = GST_D3D11_WINDOW_GET_CLASS (window);
g_assert (klass->prepare != NULL);
display_format, error);
}
-static gboolean
+static GstFlowReturn
gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
guint display_height, GstCaps * caps, GstStructure * config,
DXGI_FORMAT display_format, GError ** error)
if (config)
gst_structure_free (config);
- return FALSE;
+ return GST_FLOW_ERROR;
}
if (display_format != DXGI_FORMAT_UNKNOWN) {
if (config)
gst_structure_free (config);
- return FALSE;
+ return GST_FLOW_ERROR;
}
} else {
for (guint i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
if (config)
gst_structure_free (config);
- return FALSE;
+ return GST_FLOW_ERROR;
}
/* this rect struct will be used to calculate render area */
GST_ERROR_OBJECT (window, "Cannot create converter");
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Cannot create converter");
- return FALSE;
+ return GST_FLOW_ERROR;
}
if (have_hdr10_meta) {
GST_ERROR_OBJECT (window, "Cannot create overlay compositor");
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Cannot create overlay compositor");
- return FALSE;
+ return GST_FLOW_ERROR;
}
/* call resize to allocated resources */
GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain);
- return TRUE;
+ return GST_FLOW_OK;
}
void
/* Handle set_render_rectangle */
GstVideoRectangle render_rect;
+
+ gboolean flushing;
+ gboolean setup_external_hwnd;
};
#define gst_d3d11_window_win32_parent_class parent_class
static void gst_d3d11_window_win32_destroy_internal_window (HWND hwnd);
static void gst_d3d11_window_win32_release_external_handle (HWND hwnd);
static void
-gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
- guintptr handle);
-static void
gst_d3d11_window_win32_on_resize (GstD3D11Window * window,
guint width, guint height);
+static GstFlowReturn gst_d3d11_window_win32_prepare (GstD3D11Window * window,
+ guint display_width, guint display_height, GstCaps * caps,
+ GstStructure * config, DXGI_FORMAT display_format, GError ** error);
static void gst_d3d11_window_win32_unprepare (GstD3D11Window * window);
static void
gst_d3d11_window_win32_set_render_rectangle (GstD3D11Window * window,
const GstVideoRectangle * rect);
static void gst_d3d11_window_win32_set_title (GstD3D11Window * window,
const gchar * title);
+static gboolean gst_d3d11_window_win32_unlock (GstD3D11Window * window);
+static gboolean gst_d3d11_window_win32_unlock_stop (GstD3D11Window * window);
+static GstFlowReturn
+gst_d3d11_window_win32_set_external_handle (GstD3D11WindowWin32 * self);
static void
gst_d3d11_window_win32_class_init (GstD3D11WindowWin32Class * klass)
window_class->present = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_present);
window_class->on_resize =
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_on_resize);
+ window_class->prepare = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_prepare);
window_class->unprepare =
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_unprepare);
window_class->set_render_rectangle =
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_set_render_rectangle);
window_class->set_title =
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_set_title);
+ window_class->unlock = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_unlock);
+ window_class->unlock_stop =
+ GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_unlock_stop);
}
static void
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
if (window->external_handle) {
- gst_d3d11_window_win32_set_window_handle (self, window->external_handle);
+ /* Will setup internal child window on ::prepare() */
+ self->setup_external_hwnd = TRUE;
+ window->initialized = TRUE;
goto done;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
+static GstFlowReturn
+gst_d3d11_window_win32_prepare (GstD3D11Window * window, guint display_width,
+ guint display_height, GstCaps * caps, GstStructure * config,
+ DXGI_FORMAT display_format, GError ** error)
+{
+ GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
+ HWND hwnd;
+ GstFlowReturn ret;
+
+ if (!self->setup_external_hwnd)
+ goto done;
+
+ hwnd = (HWND) window->external_handle;
+ if (!IsWindow (hwnd)) {
+ GST_ERROR_OBJECT (self, "Invalid window handle");
+ g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
+ "Invalid window handle");
+ return GST_FLOW_ERROR;
+ }
+
+ self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE;
+ self->external_hwnd = hwnd;
+
+ GST_DEBUG_OBJECT (self, "Preparing external handle");
+ ret = gst_d3d11_window_win32_set_external_handle (self);
+ if (ret != GST_FLOW_OK) {
+ if (ret == GST_FLOW_FLUSHING) {
+ GST_WARNING_OBJECT (self, "Flushing");
+ return GST_FLOW_FLUSHING;
+ }
+
+ GST_ERROR_OBJECT (self, "Couldn't configure internal window");
+ g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
+ "Window handle configuration failed");
+ return GST_FLOW_ERROR;
+ }
+
+ GST_DEBUG_OBJECT (self, "External handle got prepared");
+ self->setup_external_hwnd = FALSE;
+
+done:
+ return GST_D3D11_WINDOW_CLASS (parent_class)->prepare (window, display_width,
+ display_height, caps, config, display_format, error);
+}
+
static void
gst_d3d11_window_win32_unprepare (GstD3D11Window * window)
{
}
static gboolean
+gst_d3d11_window_win32_unlock (GstD3D11Window * window)
+{
+ GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
+ GstD3D11SRWLockGuard lk (&self->lock);
+
+ GST_DEBUG_OBJECT (self, "Unlock");
+
+ self->flushing = TRUE;
+ WakeAllConditionVariable (&self->cond);
+
+ return TRUE;
+}
+
+static gboolean
+gst_d3d11_window_win32_unlock_stop (GstD3D11Window * window)
+{
+ GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
+ GstD3D11SRWLockGuard lk (&self->lock);
+
+ GST_DEBUG_OBJECT (self, "Unlock stop");
+
+ self->flushing = FALSE;
+ WakeAllConditionVariable (&self->cond);
+
+ return TRUE;
+}
+
+static gboolean
running_cb (gpointer user_data)
{
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (user_data);
", 0x%x", (guintptr) hwnd, (guint) GetLastError ());
}
-static void
+static GstFlowReturn
gst_d3d11_window_win32_set_external_handle (GstD3D11WindowWin32 * self)
{
WNDPROC external_window_proc;
+ GstFlowReturn ret = GST_FLOW_OK;
external_window_proc =
(WNDPROC) GetWindowLongPtrA (self->external_hwnd, GWLP_WNDPROC);
SetWindowLongPtrA (self->external_hwnd, GWLP_WNDPROC,
(LONG_PTR) sub_class_proc);
- /* Will create our internal window on parent window's thread */
- SendMessageA (self->external_hwnd, WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW,
+ /* SendMessage() may cause deadlock if parent window thread is busy
+ * for changing pipeline's state. Post our message instead, and wait for
+ * the parent window's thread or flushing */
+ PostMessageA (self->external_hwnd, WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW,
0, 0);
+
+ GstD3D11SRWLockGuard lk (&self->lock);
+ while (self->external_hwnd &&
+ self->overlay_state == GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE &&
+ !self->flushing) {
+ SleepConditionVariableSRW (&self->cond, &self->lock, INFINITE, 0);
+ }
+
+ if (self->overlay_state != GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED) {
+ if (self->flushing)
+ ret = GST_FLOW_FLUSHING;
+ else
+ ret = GST_FLOW_ERROR;
+ }
+
+ return ret;
}
static void
MoveWindow (self->internal_hwnd, rect.left, rect.top, rect.right,
rect.bottom, FALSE);
+ GstD3D11SRWLockGuard lk (&self->lock);
+ self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED;
+ WakeAllConditionVariable (&self->cond);
+
/* don't need to be chained up to parent window procedure,
* as this is our custom message */
return 0;
gst_d3d11_window_win32_release_external_handle (self->external_hwnd);
self->external_hwnd = NULL;
- RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
- ShowWindow (self->internal_hwnd, SW_HIDE);
- gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
+ if (self->internal_hwnd) {
+ RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
+ ShowWindow (self->internal_hwnd, SW_HIDE);
+ gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
+ }
self->internal_hwnd = NULL;
self->internal_hwnd_thread = NULL;
self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED;
+ WakeAllConditionVariable (&self->cond);
} else {
gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
lParam);
}
static void
-gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
- guintptr handle)
-{
- self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE;
-
- self->external_hwnd = (HWND) handle;
- gst_d3d11_window_win32_set_external_handle (self);
-
- self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED;
-}
-
-static void
gst_d3d11_window_win32_show (GstD3D11Window * window)
{
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);