summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/directdraw/gstdirectdrawsink.c181
1 files changed, 143 insertions, 38 deletions
diff --git a/sys/directdraw/gstdirectdrawsink.c b/sys/directdraw/gstdirectdrawsink.c
index 65c3df23..78406d27 100644
--- a/sys/directdraw/gstdirectdrawsink.c
+++ b/sys/directdraw/gstdirectdrawsink.c
@@ -146,13 +146,24 @@ gst_directdraw_sink_set_window_id (GstXOverlay * overlay, ULONG window_id)
{
GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
+ GST_OBJECT_LOCK (ddrawsink);
/* check if we are already using this window id */
- if (ddrawsink->video_window == (HWND) window_id)
+ if (ddrawsink->video_window == (HWND) window_id) {
+ GST_OBJECT_UNLOCK (ddrawsink);
return;
+ }
if (window_id) {
HRESULT hres;
+ /* If we had an internal window, close it first */
+ if (ddrawsink->video_window && ddrawsink->our_video_window) {
+ /* Trick to let the event thread know that it has to die silently */
+ ddrawsink->our_video_window = FALSE;
+ /* Post quit message and wait for our event window thread */
+ PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
+ }
+
ddrawsink->video_window = (HWND) window_id;
ddrawsink->our_video_window = FALSE;
if (ddrawsink->setup) {
@@ -161,6 +172,9 @@ gst_directdraw_sink_set_window_id (GstXOverlay * overlay, ULONG window_id)
ddrawsink->video_window);
}
}
+ /* FIXME: Handle the case where window_id is 0 and we want the sink to
+ * create a new window when playback was already started (after set_caps) */
+ GST_OBJECT_UNLOCK (ddrawsink);
}
static void
@@ -476,6 +490,11 @@ gst_directdraw_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ddrawsink));
}
+ /* If we still don't have a window at that stage we create our own */
+ if (!ddrawsink->video_window) {
+ gst_directdraw_sink_create_default_window (ddrawsink);
+ }
+
/* if we are rendering to our own window, resize it to video size */
if (ddrawsink->video_window && ddrawsink->our_video_window) {
SetWindowPos (ddrawsink->video_window, NULL,
@@ -499,26 +518,28 @@ static GstStateChangeReturn
gst_directdraw_sink_change_state (GstElement * element,
GstStateChange transition)
{
- GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (element);;
+ GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
- if (ddrawsink->video_window == NULL)
- if (!gst_directdraw_sink_create_default_window (ddrawsink))
- return GST_STATE_CHANGE_FAILURE;
-
- if (!gst_directdraw_sink_setup_ddraw (ddrawsink))
- return GST_STATE_CHANGE_FAILURE;
+ if (!gst_directdraw_sink_setup_ddraw (ddrawsink)) {
+ ret = GST_STATE_CHANGE_FAILURE;
+ goto beach;
+ }
- if (!(ddrawsink->caps = gst_directdraw_sink_get_ddrawcaps (ddrawsink)))
- return GST_STATE_CHANGE_FAILURE;
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ if (!(ddrawsink->caps = gst_directdraw_sink_get_ddrawcaps (ddrawsink))) {
+ ret = GST_STATE_CHANGE_FAILURE;
+ goto beach;
+ }
break;
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ default:
break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
ddrawsink->fps_n = 0;
ddrawsink->fps_d = 1;
@@ -531,9 +552,12 @@ gst_directdraw_sink_change_state (GstElement * element,
if (ddrawsink->setup)
gst_directdraw_sink_cleanup (ddrawsink);
break;
+ default:
+ break;
}
- return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+beach:
+ return ret;
}
static GstFlowReturn
@@ -547,7 +571,7 @@ gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
gboolean buffercaps_unref = FALSE;
GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
- "a buffer of %d bytes was requested", size);
+ "a buffer of %u bytes was requested", size);
g_mutex_lock (ddrawsink->pool_lock);
@@ -687,6 +711,63 @@ gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
return ret;
}
+static void
+gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect)
+{
+ RECT win_rect, fill_rect;
+ POINT win_point;
+ HDC hdc;
+
+ g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
+
+ /* Get the target window rect */
+ win_point.x = 0;
+ win_point.y = 0;
+ ClientToScreen (ddrawsink->video_window, &win_point);
+ GetClientRect (ddrawsink->video_window, &win_rect);
+ OffsetRect (&win_rect, win_point.x, win_point.y);
+
+ /* We acquire a drawing context */
+ if (IDirectDrawSurface7_GetDC (ddrawsink->primary_surface, &hdc) == DD_OK) {
+ HBRUSH brush = CreateSolidBrush (RGB (0, 0, 0));
+
+ /* Left border */
+ if (dst_rect.left > win_rect.left) {
+ fill_rect.left = win_rect.left;
+ fill_rect.top = win_rect.top;
+ fill_rect.bottom = win_rect.bottom;
+ fill_rect.right = dst_rect.left;
+ FillRect (hdc, &fill_rect, brush);
+ }
+ /* Right border */
+ if (dst_rect.right < win_rect.right) {
+ fill_rect.top = win_rect.top;
+ fill_rect.left = dst_rect.right;
+ fill_rect.bottom = win_rect.bottom;
+ fill_rect.right = win_rect.right;
+ FillRect (hdc, &fill_rect, brush);
+ }
+ /* Top border */
+ if (dst_rect.top > win_rect.top) {
+ fill_rect.top = win_rect.top;
+ fill_rect.left = win_rect.left;
+ fill_rect.right = win_rect.right;
+ fill_rect.bottom = dst_rect.top;
+ FillRect (hdc, &fill_rect, brush);
+ }
+ /* Bottom border */
+ if (dst_rect.bottom < win_rect.bottom) {
+ fill_rect.top = dst_rect.bottom;
+ fill_rect.left = win_rect.left;
+ fill_rect.right = win_rect.right;
+ fill_rect.bottom = win_rect.bottom;
+ FillRect (hdc, &fill_rect, brush);
+ }
+ DeleteObject (brush);
+ IDirectDrawSurface7_ReleaseDC (ddrawsink->primary_surface, hdc);
+ }
+}
+
static GstFlowReturn
gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
@@ -711,6 +792,15 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
return GST_FLOW_ERROR;
/* get the video window position */
+ GST_OBJECT_LOCK (ddrawsink);
+ if (G_UNLIKELY (!ddrawsink->video_window)) {
+ GST_OBJECT_UNLOCK (ddrawsink);
+ GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
+ "gst_directdraw_sink_show_frame our video window disappeared");
+ GST_ELEMENT_ERROR (ddrawsink, RESOURCE, NOT_FOUND,
+ ("Output window was closed"), (NULL));
+ return GST_FLOW_ERROR;
+ }
dest_surf_point.x = 0;
dest_surf_point.y = 0;
ClientToScreen (ddrawsink->video_window, &dest_surf_point);
@@ -725,7 +815,9 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
src_rect.right = ddrawsink->video_width;
gst_directdraw_sink_center_rect (ddrawsink, src_rect, destsurf_rect,
&destsurf_rect);
+ gst_directdraw_sink_draw_borders (ddrawsink, destsurf_rect);
}
+ GST_OBJECT_UNLOCK (ddrawsink);
if (ddrawsink->must_recreate_offscreen && ddrawsink->offscreen_surface) {
IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
@@ -780,17 +872,18 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
return GST_FLOW_ERROR;
}
- /* blit to primary surface ( Blt will scale the video the dest rect surface if needed */
+ /* blit to primary surface ( Blt will scale the video the dest rect surface
+ * if needed */
hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
ddrawsink->offscreen_surface, NULL, DDBLT_WAIT, NULL);
- if (hRes != DD_OK)
+ if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
"IDirectDrawSurface7_Blt (object's offscreen surface) " "returned %s",
DDErrorString (hRes));
} else {
- /* We are receiving a directdraw surface (previously returned by our buffer pool
- So we will simply blit it on the primary surface */
+ /* We are receiving a directdraw surface (previously returned by our buffer
+ * pool so we will simply blit it on the primary surface */
GstDDrawSurface *surface = NULL;
surface = GST_DDRAWSURFACE (buf);
@@ -802,7 +895,7 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
/* blit to our primary surface */
hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
surface->surface, NULL, DDBLT_WAIT, NULL);
- if (hRes != DD_OK)
+ if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
"IDirectDrawSurface7_Blt (offscreen surface from buffer_alloc) "
"returned %s", DDErrorString (hRes));
@@ -1158,8 +1251,8 @@ gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
gboolean bRet = TRUE;
HRESULT hRes;
- /* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first parameter to
- force Directdraw to use the hardware emulation layer */
+ /* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first
+ * parameter to force Directdraw to use the hardware emulation layer */
hRes = DirectDrawCreateEx ( /*DDCREATE_EMULATIONONLY */ 0,
(void **) &ddrawsink->ddraw_object, &IID_IDirectDraw7, NULL);
if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
@@ -1171,7 +1264,7 @@ gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
/* set cooperative level */
hRes = IDirectDraw7_SetCooperativeLevel (ddrawsink->ddraw_object,
- ddrawsink->video_window, DDSCL_NORMAL);
+ NULL, DDSCL_NORMAL);
if (hRes != DD_OK) {
GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
("Failed to set the set the cooperative level error=%s",
@@ -1182,10 +1275,6 @@ gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
/* setup the clipper object */
hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
&ddrawsink->clipper, NULL);
- if (hRes == DD_OK) {
- hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
- ddrawsink->video_window);
- }
/* create our primary surface */
if (!gst_directdraw_sink_check_primary_surface (ddrawsink))
@@ -1236,6 +1325,9 @@ gst_directdraw_sink_window_thread (GstDirectDrawSink * ddrawsink)
if (ddrawsink->video_window == NULL)
return FALSE;
+ /* Set the clipper on that window */
+ IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
+
/* signal application we create a window */
gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ddrawsink),
(gulong) ddrawsink->video_window);
@@ -1246,8 +1338,18 @@ gst_directdraw_sink_window_thread (GstDirectDrawSink * ddrawsink)
while (1) {
MSG msg;
- if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
+ if (GetMessage (&msg, ddrawsink->video_window, 0, 0) <= 0) {
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
+ "our window received WM_QUIT or error.");
+ /* The window could have changed, if it is not ours anymore we don't
+ * overwrite the current video window with NULL */
+ if (ddrawsink->our_video_window) {
+ GST_OBJECT_LOCK (ddrawsink);
+ ddrawsink->video_window = NULL;
+ GST_OBJECT_UNLOCK (ddrawsink);
+ }
break;
+ }
DispatchMessage (&msg);
}
@@ -1511,7 +1613,8 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
IDirectDraw7_GetCaps (ddrawsink->ddraw_object, &ddcaps_hardware,
&ddcaps_emulation);
- /* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw emulation layer can do it */
+ /* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw
+ * emulation layer can do it */
if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
DDSURFACEDESC2 surface_desc;
DDSURFACEDESC2 *sd;
@@ -1574,7 +1677,8 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
return NULL;
}
- /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s", gst_caps_to_string (ddrawsink->caps)); */
+ /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
+ * gst_caps_to_string (ddrawsink->caps)); */
return ddrawsink->caps;
}
@@ -1619,12 +1723,13 @@ gst_directdraw_sink_surface_create (GstDirectDrawSink * ddrawsink,
"failed getting pixel format from caps %" GST_PTR_FORMAT, caps);
}
- /* disable return of directdraw surface to buffer alloc because actually I have no solution
- * to handle display mode changes. The problem is that when the display mode is changed
- * surface's memory is freed then the upstream filter would crash trying to write to this memory.
- * Directdraw has a system lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
- * when a surface memory is locked but we need to disable this lock to return multiple buffers (surfaces)
- * and do not lock directdraw API calls.
+ /* disable return of directdraw surface to buffer alloc because actually I
+ * have no solution to handle display mode changes. The problem is that when
+ * the display mode is changed surface's memory is freed then the upstream
+ * filter would crash trying to write to this memory. Directdraw has a system
+ * lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
+ * when a surface memory is locked but we need to disable this lock to return
+ * multiple buffers (surfaces) and do not lock directdraw API calls.
*/
#if 0
/* if (ddrawsink->ddraw_object) {*/