2 * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
3 * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * The development of this code was made possible due to the involvement
21 * of Pioneers of the Inevitable, the creators of the Songbird Music player
26 * SECTION:element-directdrawsink
28 * DirectdrawSink renders video RGB frames to any win32 window. This element
29 * can receive a window ID from the application through the #XOverlay interface
30 * and will then render video frames in this window.
31 * If no Window ID was provided by the application, the element will create its
32 * own internal window and render into it.
35 * <title>Example pipelines</title>
37 * gst-launch-0.10 -v videotestsrc ! directdrawsink
38 * ]| a simple pipeline to test the sink
46 #include "gstdirectdrawsink.h"
48 GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
49 #define GST_CAT_DEFAULT directdrawsink_debug
51 /* elementfactory information */
52 static const GstElementDetails gst_directdraw_sink_details =
53 GST_ELEMENT_DETAILS ("Direct Draw Video Sink",
55 "Output to a video card via Direct Draw",
56 "Sebastien Moutte <sebastien@moutte.net>");
58 static void gst_directdraw_sink_init_interfaces (GType type);
60 GST_BOILERPLATE_FULL (GstDirectDrawSink, gst_directdraw_sink, GstVideoSink,
61 GST_TYPE_VIDEO_SINK, gst_directdraw_sink_init_interfaces);
63 static void gst_directdraw_sink_finalize (GObject * object);
64 static void gst_directdraw_sink_set_property (GObject * object,
65 guint prop_id, const GValue * value, GParamSpec * pspec);
66 static void gst_directdraw_sink_get_property (GObject * object,
67 guint prop_id, GValue * value, GParamSpec * pspec);
68 static GstCaps *gst_directdraw_sink_get_caps (GstBaseSink * bsink);
69 static gboolean gst_directdraw_sink_set_caps (GstBaseSink * bsink,
71 static GstStateChangeReturn gst_directdraw_sink_change_state (GstElement *
72 element, GstStateChange transition);
73 static GstFlowReturn gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink,
74 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
75 static void gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
76 GstClockTime * start, GstClockTime * end);
77 static GstFlowReturn gst_directdraw_sink_show_frame (GstBaseSink * bsink,
81 static gboolean gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink);
82 static gboolean gst_directdraw_sink_create_default_window (GstDirectDrawSink *
84 static gboolean gst_directdraw_sink_check_primary_surface (GstDirectDrawSink *
86 static gboolean gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink *
88 static GstCaps *gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink *
91 * gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc);
92 static void gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink);
93 static void gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink *
95 static int gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat);
96 static gboolean gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink *
97 ddrawsink, GstCaps * caps, DDPIXELFORMAT * pPixelFormat);
98 static void gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink,
99 RECT src, RECT dst, RECT * result);
100 char *DDErrorString (HRESULT hr);
102 /* surfaces management functions */
103 static void gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
104 GstDDrawSurface * surface);
105 static GstDDrawSurface *gst_directdraw_sink_surface_create (GstDirectDrawSink *
106 ddrawsink, GstCaps * caps, size_t size);
107 static gboolean gst_directdraw_sink_surface_check (GstDirectDrawSink *
108 ddrawsink, GstDDrawSurface * surface);
110 static GstStaticPadTemplate directdrawsink_sink_factory =
111 GST_STATIC_PAD_TEMPLATE ("sink",
114 GST_STATIC_CAPS ("video/x-raw-rgb, "
115 "framerate = (fraction) [ 0, MAX ], "
116 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
122 PROP_KEEP_ASPECT_RATIO
125 /* XOverlay interface implementation */
127 gst_directdraw_sink_interface_supported (GstImplementsInterface * iface,
130 g_assert (type == GST_TYPE_X_OVERLAY);
135 gst_directdraw_sink_interface_init (GstImplementsInterfaceClass * klass)
137 klass->supported = gst_directdraw_sink_interface_supported;
141 gst_directdraw_sink_set_window_id (GstXOverlay * overlay, ULONG window_id)
143 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
145 GST_OBJECT_LOCK (ddrawsink);
146 /* check if we are already using this window id */
147 if (ddrawsink->video_window == (HWND) window_id) {
148 GST_OBJECT_UNLOCK (ddrawsink);
155 /* If we had an internal window, close it first */
156 if (ddrawsink->video_window && ddrawsink->our_video_window) {
157 /* Trick to let the event thread know that it has to die silently */
158 ddrawsink->our_video_window = FALSE;
159 /* Post quit message and wait for our event window thread */
160 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
163 ddrawsink->video_window = (HWND) window_id;
164 ddrawsink->our_video_window = FALSE;
165 if (ddrawsink->setup) {
166 /* update the clipper object with the new window */
167 hres = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
168 ddrawsink->video_window);
171 /* FIXME: Handle the case where window_id is 0 and we want the sink to
172 * create a new window when playback was already started (after set_caps) */
173 GST_OBJECT_UNLOCK (ddrawsink);
177 gst_directdraw_sink_expose (GstXOverlay * overlay)
179 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
181 gst_directdraw_sink_show_frame (GST_BASE_SINK (ddrawsink), NULL);
185 gst_directdraw_sink_xoverlay_interface_init (GstXOverlayClass * iface)
187 iface->set_xwindow_id = gst_directdraw_sink_set_window_id;
188 iface->expose = gst_directdraw_sink_expose;
192 gst_directdraw_sink_init_interfaces (GType type)
194 static const GInterfaceInfo iface_info = {
195 (GInterfaceInitFunc) gst_directdraw_sink_interface_init,
200 static const GInterfaceInfo xoverlay_info = {
201 (GInterfaceInitFunc) gst_directdraw_sink_xoverlay_interface_init,
206 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
208 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
211 /* Subclass of GstBuffer which manages buffer_pool surfaces lifetime */
212 static void gst_ddrawsurface_finalize (GstMiniObject * mini_object);
213 static GstBufferClass *ddrawsurface_parent_class = NULL;
216 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
218 surface->surface = NULL;
221 surface->ddrawsink = NULL;
222 surface->locked = FALSE;
223 surface->system_memory = FALSE;
224 memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
228 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
230 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
232 ddrawsurface_parent_class = g_type_class_peek_parent (g_class);
234 mini_object_class->finalize = GST_DEBUG_FUNCPTR (gst_ddrawsurface_finalize);
238 gst_ddrawsurface_get_type (void)
240 static GType _gst_ddrawsurface_type;
242 if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
243 static const GTypeInfo ddrawsurface_info = {
244 sizeof (GstBufferClass),
247 gst_ddrawsurface_class_init,
250 sizeof (GstDDrawSurface),
252 (GInstanceInitFunc) gst_ddrawsurface_init,
255 _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
256 "GstDDrawSurface", &ddrawsurface_info, 0);
258 return _gst_ddrawsurface_type;
262 gst_ddrawsurface_finalize (GstMiniObject * mini_object)
264 GstDirectDrawSink *ddrawsink = NULL;
265 GstDDrawSurface *surface;
267 surface = (GstDDrawSurface *) mini_object;
269 ddrawsink = surface->ddrawsink;
273 /* If our geometry changed we can't reuse that image. */
274 if ((surface->width != ddrawsink->video_width) ||
275 (surface->height != ddrawsink->video_height) ||
276 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
277 sizeof (DDPIXELFORMAT)) != 0 ||
278 !gst_directdraw_sink_surface_check (ddrawsink, surface))
280 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
281 "destroy image as its size changed %dx%d vs current %dx%d",
282 surface->width, surface->height, ddrawsink->video_width,
283 ddrawsink->video_height);
284 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
285 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
287 /* In that case we can reuse the image and add it to our image pool. */
288 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
289 "recycling image in pool");
291 /* need to increment the refcount again to recycle */
292 gst_buffer_ref (GST_BUFFER (surface));
294 g_mutex_lock (ddrawsink->pool_lock);
295 ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
296 g_mutex_unlock (ddrawsink->pool_lock);
302 GST_CAT_WARNING (directdrawsink_debug, "no sink found");
303 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
307 /************************************************************************/
308 /* Directdraw sink functions */
309 /************************************************************************/
311 gst_directdraw_sink_base_init (gpointer g_class)
313 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
315 gst_element_class_set_details (element_class, &gst_directdraw_sink_details);
316 gst_element_class_add_pad_template (element_class,
317 gst_static_pad_template_get (&directdrawsink_sink_factory));
321 gst_directdraw_sink_class_init (GstDirectDrawSinkClass * klass)
323 GObjectClass *gobject_class;
324 GstElementClass *gstelement_class;
325 GstBaseSinkClass *gstbasesink_class;
327 gobject_class = (GObjectClass *) klass;
328 gstbasesink_class = (GstBaseSinkClass *) klass;
329 gstelement_class = (GstElementClass *) klass;
331 GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
334 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdraw_sink_finalize);
335 gobject_class->get_property =
336 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_property);
337 gobject_class->set_property =
338 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_property);
339 gstelement_class->change_state =
340 GST_DEBUG_FUNCPTR (gst_directdraw_sink_change_state);
341 gstbasesink_class->get_caps =
342 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_caps);
343 gstbasesink_class->set_caps =
344 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_caps);
345 gstbasesink_class->preroll =
346 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
347 gstbasesink_class->render =
348 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
349 gstbasesink_class->get_times =
350 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_times);
351 gstbasesink_class->buffer_alloc =
352 GST_DEBUG_FUNCPTR (gst_directdraw_sink_buffer_alloc);
354 /* install properties */
355 /* setup aspect ratio mode */
356 g_object_class_install_property (G_OBJECT_CLASS (klass),
357 PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("force-aspect-ratio",
358 "Force aspect ratio",
359 "When enabled, scaling will respect original aspect ratio", FALSE,
364 gst_directdraw_sink_set_property (GObject * object, guint prop_id,
365 const GValue * value, GParamSpec * pspec)
367 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
370 case PROP_KEEP_ASPECT_RATIO:
371 ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380 gst_directdraw_sink_get_property (GObject * object, guint prop_id,
381 GValue * value, GParamSpec * pspec)
383 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
386 case PROP_KEEP_ASPECT_RATIO:
387 g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
390 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
396 gst_directdraw_sink_finalize (GObject * object)
398 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
400 if (ddrawsink->pool_lock) {
401 g_mutex_free (ddrawsink->pool_lock);
402 ddrawsink->pool_lock = NULL;
404 if (ddrawsink->caps) {
405 gst_caps_unref (ddrawsink->caps);
406 ddrawsink->caps = NULL;
408 if (ddrawsink->setup) {
409 gst_directdraw_sink_cleanup (ddrawsink);
412 G_OBJECT_CLASS (parent_class)->finalize (object);
416 gst_directdraw_sink_init (GstDirectDrawSink * ddrawsink,
417 GstDirectDrawSinkClass * g_class)
419 /*init members variables */
420 ddrawsink->ddraw_object = NULL;
421 ddrawsink->primary_surface = NULL;
422 ddrawsink->offscreen_surface = NULL;
423 ddrawsink->clipper = NULL;
424 ddrawsink->video_window = NULL;
425 ddrawsink->our_video_window = TRUE;
426 ddrawsink->last_buffer = NULL;
427 ddrawsink->caps = NULL;
428 ddrawsink->window_thread = NULL;
429 ddrawsink->setup = FALSE;
430 ddrawsink->buffer_pool = NULL;
431 ddrawsink->keep_aspect_ratio = FALSE;
432 ddrawsink->pool_lock = g_mutex_new ();
433 ddrawsink->can_blit_between_colorspace = TRUE;
434 ddrawsink->must_recreate_offscreen = FALSE;
435 memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
437 /*video default values */
438 ddrawsink->video_height = 0;
439 ddrawsink->video_width = 0;
440 ddrawsink->fps_n = 0;
441 ddrawsink->fps_d = 0;
445 gst_directdraw_sink_get_caps (GstBaseSink * bsink)
447 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
448 GstCaps *caps = NULL;
450 if (!ddrawsink->setup) {
451 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
453 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
454 "getcaps called and we are not setup yet, " "returning template %"
455 GST_PTR_FORMAT, caps);
457 caps = gst_caps_ref (ddrawsink->caps);
464 gst_directdraw_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
466 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
467 GstStructure *structure = NULL;
471 structure = gst_caps_get_structure (caps, 0);
475 ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
476 ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
477 fps = gst_structure_get_value (structure, "framerate");
478 ret &= (fps != NULL);
480 gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
481 &ddrawsink->dd_pixel_format);
483 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
484 ("Failed to get caps properties from caps"), (NULL));
488 ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
489 ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
491 /* Notify application to set window id now */
492 if (!ddrawsink->video_window) {
493 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ddrawsink));
496 /* If we still don't have a window at that stage we create our own */
497 if (!ddrawsink->video_window) {
498 gst_directdraw_sink_create_default_window (ddrawsink);
501 /* if we are rendering to our own window, resize it to video size */
502 if (ddrawsink->video_window && ddrawsink->our_video_window) {
503 SetWindowPos (ddrawsink->video_window, NULL,
504 0, 0, ddrawsink->video_width + (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
505 ddrawsink->video_height + GetSystemMetrics (SM_CYCAPTION) +
506 (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
509 /* release the surface, we have to recreate it! */
510 if (ddrawsink->offscreen_surface) {
511 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
512 ddrawsink->offscreen_surface = NULL;
515 /* create an offscreen surface with the caps */
516 ret = gst_directdraw_sink_check_offscreen_surface (ddrawsink);
518 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
519 ("Can't create a directdraw offscreen surface with the input caps"),
526 static GstStateChangeReturn
527 gst_directdraw_sink_change_state (GstElement * element,
528 GstStateChange transition)
530 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (element);
531 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
533 switch (transition) {
534 case GST_STATE_CHANGE_NULL_TO_READY:
535 if (!gst_directdraw_sink_setup_ddraw (ddrawsink)) {
536 ret = GST_STATE_CHANGE_FAILURE;
540 if (!(ddrawsink->caps = gst_directdraw_sink_get_ddrawcaps (ddrawsink))) {
541 ret = GST_STATE_CHANGE_FAILURE;
549 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
551 switch (transition) {
552 case GST_STATE_CHANGE_PAUSED_TO_READY:
553 ddrawsink->fps_n = 0;
554 ddrawsink->fps_d = 1;
555 ddrawsink->video_width = 0;
556 ddrawsink->video_height = 0;
557 if (ddrawsink->buffer_pool)
558 gst_directdraw_sink_bufferpool_clear (ddrawsink);
560 case GST_STATE_CHANGE_READY_TO_NULL:
561 if (ddrawsink->setup)
562 gst_directdraw_sink_cleanup (ddrawsink);
573 gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
574 guint size, GstCaps * caps, GstBuffer ** buf)
576 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
577 GstStructure *structure;
579 GstDDrawSurface *surface = NULL;
580 GstFlowReturn ret = GST_FLOW_OK;
581 GstCaps *buffer_caps = caps;
582 gboolean buffercaps_unref = FALSE;
584 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
585 "a buffer of %u bytes was requested", size);
587 structure = gst_caps_get_structure (caps, 0);
588 if (!gst_structure_get_int (structure, "width", &width) ||
589 !gst_structure_get_int (structure, "height", &height)) {
590 GST_WARNING_OBJECT (ddrawsink, "invalid caps for buffer allocation %"
591 GST_PTR_FORMAT, caps);
592 return GST_FLOW_UNEXPECTED;
595 g_mutex_lock (ddrawsink->pool_lock);
597 /* Inspect our buffer pool */
598 while (ddrawsink->buffer_pool) {
599 surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
601 /* Removing from the pool */
602 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
603 ddrawsink->buffer_pool);
605 /* If the surface is invalid for our need, destroy */
606 if ((surface->width != width) ||
607 (surface->height != height) ||
608 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
609 sizeof (DDPIXELFORMAT)) ||
610 !gst_directdraw_sink_surface_check (ddrawsink, surface))
612 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
613 gst_buffer_unref (surface);
616 /* We found a suitable surface */
622 if (!ddrawsink->can_blit_between_colorspace) {
623 /* Hardware doesn't support blit from one colorspace to another.
624 * Check if the colorspace of the current display mode has changed since
625 * the last negociation. If it's the case, we will have to renegociate
629 DDSURFACEDESC2 surface_desc;
632 if (!gst_structure_get_int (structure, "depth", &depth)) {
633 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
634 "Can't get depth from buffer_alloc caps");
635 return GST_FLOW_ERROR;
637 surface_desc.dwSize = sizeof (surface_desc);
640 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
641 (DDSURFACEDESC *) sd);
643 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
644 "Can't get current display mode (error=%ld)", (glong) hres);
645 return GST_FLOW_ERROR;
648 if (depth != gst_directdraw_sink_get_depth (&surface_desc.ddpfPixelFormat)) {
649 GstCaps *copy_caps = NULL;
650 GstStructure *copy_structure = NULL;
651 GstCaps *display_caps = NULL;
652 GstStructure *display_structure = NULL;
654 /* make a copy of the original caps */
655 copy_caps = gst_caps_copy (caps);
656 copy_structure = gst_caps_get_structure (copy_caps, 0);
659 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
661 display_structure = gst_caps_get_structure (display_caps, 0);
662 if (display_structure) {
663 gint bpp, endianness, red_mask, green_mask, blue_mask;
665 /* get new display mode properties */
666 gst_structure_get_int (display_structure, "depth", &depth);
667 gst_structure_get_int (display_structure, "bpp", &bpp);
668 gst_structure_get_int (display_structure, "endianness", &endianness);
669 gst_structure_get_int (display_structure, "red_mask", &red_mask);
670 gst_structure_get_int (display_structure, "green_mask", &green_mask);
671 gst_structure_get_int (display_structure, "blue_mask", &blue_mask);
673 /* apply the new display mode changes to the previous caps */
674 gst_structure_set (copy_structure,
675 "bpp", G_TYPE_INT, bpp,
676 "depth", G_TYPE_INT, depth,
677 "endianness", G_TYPE_INT, endianness,
678 "red_mask", G_TYPE_INT, red_mask,
679 "green_mask", G_TYPE_INT, green_mask,
680 "blue_mask", G_TYPE_INT, blue_mask, NULL);
682 if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ddrawsink),
684 buffer_caps = copy_caps;
685 buffercaps_unref = TRUE;
686 /* update buffer size needed to store video frames according to new caps */
687 size = width * height * (bpp / 8);
689 /* update our member pixel format */
690 gst_ddrawvideosink_get_format_from_caps (ddrawsink, buffer_caps,
691 &ddrawsink->dd_pixel_format);
692 ddrawsink->must_recreate_offscreen = TRUE;
694 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
695 " desired caps %s \n\n new caps %s", gst_caps_to_string (caps),
696 gst_caps_to_string (buffer_caps));
698 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
699 "peer refused caps re-negociation "
700 "and we can't render with the current caps.");
701 ret = GST_FLOW_ERROR;
704 gst_caps_unref (display_caps);
707 if (!buffercaps_unref)
708 gst_caps_unref (copy_caps);
712 /* We haven't found anything, creating a new one */
714 surface = gst_directdraw_sink_surface_create (ddrawsink, buffer_caps, size);
717 /* Now we should have a surface, set appropriate caps on it */
719 GST_BUFFER_FLAGS (GST_BUFFER (surface)) = 0;
720 gst_buffer_set_caps (GST_BUFFER (surface), buffer_caps);
723 g_mutex_unlock (ddrawsink->pool_lock);
725 *buf = GST_BUFFER (surface);
727 if (buffercaps_unref)
728 gst_caps_unref (buffer_caps);
734 gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect)
736 RECT win_rect, fill_rect;
740 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
742 /* Get the target window rect */
745 ClientToScreen (ddrawsink->video_window, &win_point);
746 GetClientRect (ddrawsink->video_window, &win_rect);
747 OffsetRect (&win_rect, win_point.x, win_point.y);
749 /* We acquire a drawing context */
750 if (IDirectDrawSurface7_GetDC (ddrawsink->primary_surface, &hdc) == DD_OK) {
751 HBRUSH brush = CreateSolidBrush (RGB (0, 0, 0));
754 if (dst_rect.left > win_rect.left) {
755 fill_rect.left = win_rect.left;
756 fill_rect.top = win_rect.top;
757 fill_rect.bottom = win_rect.bottom;
758 fill_rect.right = dst_rect.left;
759 FillRect (hdc, &fill_rect, brush);
762 if (dst_rect.right < win_rect.right) {
763 fill_rect.top = win_rect.top;
764 fill_rect.left = dst_rect.right;
765 fill_rect.bottom = win_rect.bottom;
766 fill_rect.right = win_rect.right;
767 FillRect (hdc, &fill_rect, brush);
770 if (dst_rect.top > win_rect.top) {
771 fill_rect.top = win_rect.top;
772 fill_rect.left = win_rect.left;
773 fill_rect.right = win_rect.right;
774 fill_rect.bottom = dst_rect.top;
775 FillRect (hdc, &fill_rect, brush);
778 if (dst_rect.bottom < win_rect.bottom) {
779 fill_rect.top = dst_rect.bottom;
780 fill_rect.left = win_rect.left;
781 fill_rect.right = win_rect.right;
782 fill_rect.bottom = win_rect.bottom;
783 FillRect (hdc, &fill_rect, brush);
785 DeleteObject (brush);
786 IDirectDrawSurface7_ReleaseDC (ddrawsink->primary_surface, hdc);
791 gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
793 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
795 RECT destsurf_rect, src_rect;
796 POINT dest_surf_point;
799 /* save a reference to the input buffer */
800 gst_buffer_ref (buf);
801 if (ddrawsink->last_buffer != NULL)
802 gst_buffer_unref (ddrawsink->last_buffer);
803 ddrawsink->last_buffer = buf;
805 /* use last buffer */
806 buf = ddrawsink->last_buffer;
810 GST_ERROR_OBJECT (ddrawsink, "No buffer to render.");
811 return GST_FLOW_ERROR;
812 } else if (!ddrawsink->video_window) {
813 GST_WARNING_OBJECT (ddrawsink, "No video window to render to.");
814 return GST_FLOW_ERROR;
817 /* get the video window position */
818 GST_OBJECT_LOCK (ddrawsink);
819 if (G_UNLIKELY (!ddrawsink->video_window)) {
820 GST_OBJECT_UNLOCK (ddrawsink);
821 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
822 "gst_directdraw_sink_show_frame our video window disappeared");
823 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, NOT_FOUND,
824 ("Output window was closed"), (NULL));
825 return GST_FLOW_ERROR;
827 dest_surf_point.x = 0;
828 dest_surf_point.y = 0;
829 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
830 GetClientRect (ddrawsink->video_window, &destsurf_rect);
831 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
833 if (ddrawsink->keep_aspect_ratio) {
834 /* center image to dest image keeping aspect ratio */
837 src_rect.bottom = ddrawsink->video_height;
838 src_rect.right = ddrawsink->video_width;
839 gst_directdraw_sink_center_rect (ddrawsink, src_rect, destsurf_rect,
841 gst_directdraw_sink_draw_borders (ddrawsink, destsurf_rect);
843 GST_OBJECT_UNLOCK (ddrawsink);
845 if (ddrawsink->must_recreate_offscreen && ddrawsink->offscreen_surface) {
846 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
847 ddrawsink->offscreen_surface = NULL;
850 /* check for surfaces lost */
851 if (!gst_directdraw_sink_check_primary_surface (ddrawsink) ||
852 !gst_directdraw_sink_check_offscreen_surface (ddrawsink)) {
853 return GST_FLOW_ERROR;
856 if (!GST_IS_DDRAWSURFACE (buf) ||
857 ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
858 /* We are receiving a system memory buffer so we will copy
859 to the memory of our offscreen surface and next blit this surface
860 on the primary surface */
862 guint src_pitch, line;
863 DDSURFACEDESC2 surf_desc;
866 ZeroMemory (&surf_desc, sizeof (surf_desc));
867 surf_desc.dwSize = sizeof (surf_desc);
870 /* Lock the surface */
872 IDirectDrawSurface7_Lock (ddrawsink->offscreen_surface, NULL,
873 (DDSURFACEDESC *) sd, DDLOCK_WAIT, NULL);
875 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
876 "gst_directdraw_sink_show_frame failed locking surface %s",
877 DDErrorString (hRes));
879 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK)
882 return GST_FLOW_ERROR;
885 /* Write each line respecting the destination surface pitch */
886 data = surf_desc.lpSurface;
887 src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
888 for (line = 0; line < surf_desc.dwHeight; line++) {
889 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
890 data += surf_desc.lPitch;
893 /* Unlock the surface */
894 hRes = IDirectDrawSurface7_Unlock (ddrawsink->offscreen_surface, NULL);
896 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
897 "gst_directdraw_sink_show_frame failed unlocking surface %s",
898 DDErrorString (hRes));
899 return GST_FLOW_ERROR;
902 /* blit to primary surface ( Blt will scale the video the dest rect surface
904 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
905 ddrawsink->offscreen_surface, NULL, DDBLT_WAIT, NULL);
906 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
907 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
908 "IDirectDrawSurface7_Blt (object's offscreen surface) " "returned %s",
909 DDErrorString (hRes));
912 /* We are receiving a directdraw surface (previously returned by our buffer
913 * pool so we will simply blit it on the primary surface */
914 GstDDrawSurface *surface = NULL;
916 surface = GST_DDRAWSURFACE (buf);
918 /* Unlocking surface before blit */
919 IDirectDrawSurface7_Unlock (surface->surface, NULL);
920 surface->locked = FALSE;
922 /* blit to our primary surface */
923 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
924 surface->surface, NULL, DDBLT_WAIT, NULL);
925 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
926 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
927 "IDirectDrawSurface7_Blt (offscreen surface from buffer_alloc) "
928 "returned %s", DDErrorString (hRes));
935 gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
936 GstClockTime * start, GstClockTime * end)
938 GstDirectDrawSink *ddrawsink;
940 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
942 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
943 *start = GST_BUFFER_TIMESTAMP (buf);
944 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
945 *end = *start + GST_BUFFER_DURATION (buf);
947 if (ddrawsink->fps_n > 0) {
948 *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
954 /* Utility functions */
956 /* this function fill a DDPIXELFORMAT using Gstreamer caps */
958 gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink * ddrawsink,
959 GstCaps * caps, DDPIXELFORMAT * pPixelFormat)
961 GstStructure *structure = NULL;
965 g_return_val_if_fail (pPixelFormat, FALSE);
966 g_return_val_if_fail (caps, FALSE);
969 memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
970 pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
972 if (!(structure = gst_caps_get_structure (caps, 0))) {
973 GST_CAT_ERROR_OBJECT (directdrawsink_debug, ddrawsink,
974 "can't get structure pointer from caps");
978 if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
979 gint depth, bitcount, bitmask, endianness;
981 pPixelFormat->dwFlags = DDPF_RGB;
982 ret &= gst_structure_get_int (structure, "bpp", &bitcount);
983 pPixelFormat->dwRGBBitCount = bitcount;
984 ret &= gst_structure_get_int (structure, "depth", &depth);
985 ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
986 pPixelFormat->dwRBitMask = bitmask;
987 ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
988 pPixelFormat->dwGBitMask = bitmask;
989 ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
990 pPixelFormat->dwBBitMask = bitmask;
992 gst_structure_get_int (structure, "endianness", &endianness);
993 if (endianness == G_BIG_ENDIAN) {
994 endianness = G_LITTLE_ENDIAN;
995 pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
996 pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
997 pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
999 } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
1002 pPixelFormat->dwFlags = DDPF_FOURCC;
1003 ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
1004 pPixelFormat->dwFourCC = fourcc;
1006 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1007 "unknown caps name received %" GST_PTR_FORMAT, caps);
1014 /* This function centers the RECT of source surface to
1015 a dest surface and set the result RECT into result */
1017 gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink, RECT src,
1018 RECT dst, RECT * result)
1020 gdouble src_ratio, dst_ratio;
1021 long src_width = src.right;
1022 long src_height = src.bottom;
1023 long dst_width = dst.right - dst.left;
1024 long dst_heigth = dst.bottom - dst.top;
1025 long result_width = 0, result_height = 0;
1027 g_return_if_fail (result != NULL);
1029 src_ratio = (gdouble) src_width / src_height;
1030 dst_ratio = (gdouble) dst_width / dst_heigth;
1032 if (src_ratio > dst_ratio) {
1034 result_height = (long) (dst_width / src_ratio);
1036 result->left = dst.left;
1037 result->right = dst.right;
1038 result->top = dst.top + (dst_heigth - result_height) / 2;
1039 result->bottom = result->top + result_height;
1041 } else if (src_ratio < dst_ratio) {
1043 result_width = (long) (dst_heigth * src_ratio);
1045 result->top = dst.top;
1046 result->bottom = dst.bottom;
1047 result->left = dst.left + (dst_width - result_width) / 2;
1048 result->right = result->left + result_width;
1052 memcpy (result, &dst, sizeof (RECT));
1055 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1056 "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
1057 src_width, src_height, dst_width, dst_heigth,
1058 result->right - result->left, result->bottom - result->top, result->left,
1063 * Get DirectDraw error message.
1065 * Returns: Text representation of the error.
1068 DDErrorString (HRESULT hr)
1071 case DDERR_ALREADYINITIALIZED:
1072 return "DDERR_ALREADYINITIALIZED";
1073 case DDERR_CANNOTATTACHSURFACE:
1074 return "DDERR_CANNOTATTACHSURFACE";
1075 case DDERR_CANNOTDETACHSURFACE:
1076 return "DDERR_CANNOTDETACHSURFACE";
1077 case DDERR_CURRENTLYNOTAVAIL:
1078 return "DDERR_CURRENTLYNOTAVAIL";
1079 case DDERR_EXCEPTION:
1080 return "DDERR_EXCEPTION";
1082 return "DDERR_GENERIC";
1083 case DDERR_HEIGHTALIGN:
1084 return "DDERR_HEIGHTALIGN";
1085 case DDERR_INCOMPATIBLEPRIMARY:
1086 return "DDERR_INCOMPATIBLEPRIMARY";
1087 case DDERR_INVALIDCAPS:
1088 return "DDERR_INVALIDCAPS";
1089 case DDERR_INVALIDCLIPLIST:
1090 return "DDERR_INVALIDCLIPLIST";
1091 case DDERR_INVALIDMODE:
1092 return "DDERR_INVALIDMODE";
1093 case DDERR_INVALIDOBJECT:
1094 return "DDERR_INVALIDOBJECT";
1095 case DDERR_INVALIDPARAMS:
1096 return "DDERR_INVALIDPARAMS";
1097 case DDERR_INVALIDPIXELFORMAT:
1098 return "DDERR_INVALIDPIXELFORMAT";
1099 case DDERR_INVALIDRECT:
1100 return "DDERR_INVALIDRECT";
1101 case DDERR_LOCKEDSURFACES:
1102 return "DDERR_LOCKEDSURFACES";
1104 return "DDERR_NO3D";
1105 case DDERR_NOALPHAHW:
1106 return "DDERR_NOALPHAHW";
1107 case DDERR_NOCLIPLIST:
1108 return "DDERR_NOCLIPLIST";
1109 case DDERR_NOCOLORCONVHW:
1110 return "DDERR_NOCOLORCONVHW";
1111 case DDERR_NOCOOPERATIVELEVELSET:
1112 return "DDERR_NOCOOPERATIVELEVELSET";
1113 case DDERR_NOCOLORKEY:
1114 return "DDERR_NOCOLORKEY";
1115 case DDERR_NOCOLORKEYHW:
1116 return "DDERR_NOCOLORKEYHW";
1117 case DDERR_NODIRECTDRAWSUPPORT:
1118 return "DDERR_NODIRECTDRAWSUPPORT";
1119 case DDERR_NOEXCLUSIVEMODE:
1120 return "DDERR_NOEXCLUSIVEMODE";
1121 case DDERR_NOFLIPHW:
1122 return "DDERR_NOFLIPHW";
1124 return "DDERR_NOGDI";
1125 case DDERR_NOMIRRORHW:
1126 return "DDERR_NOMIRRORHW";
1127 case DDERR_NOTFOUND:
1128 return "DDERR_NOTFOUND";
1129 case DDERR_NOOVERLAYHW:
1130 return "DDERR_NOOVERLAYHW";
1131 case DDERR_NORASTEROPHW:
1132 return "DDERR_NORASTEROPHW";
1133 case DDERR_NOROTATIONHW:
1134 return "DDERR_NOROTATIONHW";
1135 case DDERR_NOSTRETCHHW:
1136 return "DDERR_NOSTRETCHHW";
1137 case DDERR_NOT4BITCOLOR:
1138 return "DDERR_NOT4BITCOLOR";
1139 case DDERR_NOT4BITCOLORINDEX:
1140 return "DDERR_NOT4BITCOLORINDEX";
1141 case DDERR_NOT8BITCOLOR:
1142 return "DDERR_NOT8BITCOLOR";
1143 case DDERR_NOTEXTUREHW:
1144 return "DDERR_NOTEXTUREHW";
1145 case DDERR_NOVSYNCHW:
1146 return "DDERR_NOVSYNCHW";
1147 case DDERR_NOZBUFFERHW:
1148 return "DDERR_NOZBUFFERHW";
1149 case DDERR_NOZOVERLAYHW:
1150 return "DDERR_NOZOVERLAYHW";
1151 case DDERR_OUTOFCAPS:
1152 return "DDERR_OUTOFCAPS";
1153 case DDERR_OUTOFMEMORY:
1154 return "DDERR_OUTOFMEMORY";
1155 case DDERR_OUTOFVIDEOMEMORY:
1156 return "DDERR_OUTOFVIDEOMEMORY";
1157 case DDERR_OVERLAYCANTCLIP:
1158 return "DDERR_OVERLAYCANTCLIP";
1159 case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
1160 return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
1161 case DDERR_PALETTEBUSY:
1162 return "DDERR_PALETTEBUSY";
1163 case DDERR_COLORKEYNOTSET:
1164 return "DDERR_COLORKEYNOTSET";
1165 case DDERR_SURFACEALREADYATTACHED:
1166 return "DDERR_SURFACEALREADYATTACHED";
1167 case DDERR_SURFACEALREADYDEPENDENT:
1168 return "DDERR_SURFACEALREADYDEPENDENT";
1169 case DDERR_SURFACEBUSY:
1170 return "DDERR_SURFACEBUSY";
1171 case DDERR_CANTLOCKSURFACE:
1172 return "DDERR_CANTLOCKSURFACE";
1173 case DDERR_SURFACEISOBSCURED:
1174 return "DDERR_SURFACEISOBSCURED";
1175 case DDERR_SURFACELOST:
1176 return "DDERR_SURFACELOST";
1177 case DDERR_SURFACENOTATTACHED:
1178 return "DDERR_SURFACENOTATTACHED";
1179 case DDERR_TOOBIGHEIGHT:
1180 return "DDERR_TOOBIGHEIGHT";
1181 case DDERR_TOOBIGSIZE:
1182 return "DDERR_TOOBIGSIZE";
1183 case DDERR_TOOBIGWIDTH:
1184 return "DDERR_TOOBIGWIDTH";
1185 case DDERR_UNSUPPORTED:
1186 return "DDERR_UNSUPPORTED";
1187 case DDERR_UNSUPPORTEDFORMAT:
1188 return "DDERR_UNSUPPORTEDFORMAT";
1189 case DDERR_UNSUPPORTEDMASK:
1190 return "DDERR_UNSUPPORTEDMASK";
1191 case DDERR_VERTICALBLANKINPROGRESS:
1192 return "DDERR_VERTICALBLANKINPROGRESS";
1193 case DDERR_WASSTILLDRAWING:
1194 return "DDERR_WASSTILLDRAWING";
1196 return "DDERR_XALIGN";
1197 case DDERR_INVALIDDIRECTDRAWGUID:
1198 return "DDERR_INVALIDDIRECTDRAWGUID";
1199 case DDERR_DIRECTDRAWALREADYCREATED:
1200 return "DDERR_DIRECTDRAWALREADYCREATED";
1201 case DDERR_NODIRECTDRAWHW:
1202 return "DDERR_NODIRECTDRAWHW";
1203 case DDERR_PRIMARYSURFACEALREADYEXISTS:
1204 return "DDERR_PRIMARYSURFACEALREADYEXISTS";
1205 case DDERR_NOEMULATION:
1206 return "DDERR_NOEMULATION";
1207 case DDERR_REGIONTOOSMALL:
1208 return "DDERR_REGIONTOOSMALL";
1209 case DDERR_CLIPPERISUSINGHWND:
1210 return "DDERR_CLIPPERISUSINGHWND";
1211 case DDERR_NOCLIPPERATTACHED:
1212 return "DDERR_NOCLIPPERATTACHED";
1214 return "DDERR_NOHWND";
1215 case DDERR_HWNDSUBCLASSED:
1216 return "DDERR_HWNDSUBCLASSED";
1217 case DDERR_HWNDALREADYSET:
1218 return "DDERR_HWNDALREADYSET";
1219 case DDERR_NOPALETTEATTACHED:
1220 return "DDERR_NOPALETTEATTACHED";
1221 case DDERR_NOPALETTEHW:
1222 return "DDERR_NOPALETTEHW";
1223 case DDERR_BLTFASTCANTCLIP:
1224 return "DDERR_BLTFASTCANTCLIP";
1226 return "DDERR_NOBLTHW";
1227 case DDERR_NODDROPSHW:
1228 return "DDERR_NODDROPSHW";
1229 case DDERR_OVERLAYNOTVISIBLE:
1230 return "DDERR_OVERLAYNOTVISIBLE";
1231 case DDERR_NOOVERLAYDEST:
1232 return "DDERR_NOOVERLAYDEST";
1233 case DDERR_INVALIDPOSITION:
1234 return "DDERR_INVALIDPOSITION";
1235 case DDERR_NOTAOVERLAYSURFACE:
1236 return "DDERR_NOTAOVERLAYSURFACE";
1237 case DDERR_EXCLUSIVEMODEALREADYSET:
1238 return "DDERR_EXCLUSIVEMODEALREADYSET";
1239 case DDERR_NOTFLIPPABLE:
1240 return "DDERR_NOTFLIPPABLE";
1241 case DDERR_CANTDUPLICATE:
1242 return "DDERR_CANTDUPLICATE";
1243 case DDERR_NOTLOCKED:
1244 return "DDERR_NOTLOCKED";
1245 case DDERR_CANTCREATEDC:
1246 return "DDERR_CANTCREATEDC";
1248 return "DDERR_NODC";
1249 case DDERR_WRONGMODE:
1250 return "DDERR_WRONGMODE";
1251 case DDERR_IMPLICITLYCREATED:
1252 return "DDERR_IMPLICITLYCREATED";
1253 case DDERR_NOTPALETTIZED:
1254 return "DDERR_NOTPALETTIZED";
1255 case DDERR_UNSUPPORTEDMODE:
1256 return "DDERR_UNSUPPORTEDMODE";
1257 case DDERR_NOMIPMAPHW:
1258 return "DDERR_NOMIPMAPHW";
1259 case DDERR_INVALIDSURFACETYPE:
1260 return "DDERR_INVALIDSURFACETYPE";
1261 case DDERR_DCALREADYCREATED:
1262 return "DDERR_DCALREADYCREATED";
1263 case DDERR_CANTPAGELOCK:
1264 return "DDERR_CANTPAGELOCK";
1265 case DDERR_CANTPAGEUNLOCK:
1266 return "DDERR_CANTPAGEUNLOCK";
1267 case DDERR_NOTPAGELOCKED:
1268 return "DDERR_NOTPAGELOCKED";
1269 case DDERR_NOTINITIALIZED:
1270 return "DDERR_NOTINITIALIZED";
1272 return "Unknown Error";
1276 gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1278 gboolean bRet = TRUE;
1281 /* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first
1282 * parameter to force Directdraw to use the hardware emulation layer */
1283 hRes = DirectDrawCreateEx ( /*DDCREATE_EMULATIONONLY */ 0,
1284 (void **) &ddrawsink->ddraw_object, &IID_IDirectDraw7, NULL);
1285 if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
1286 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1287 ("Failed to create the DirectDraw object error=%s",
1288 DDErrorString (hRes)), (NULL));
1292 /* set cooperative level */
1293 hRes = IDirectDraw7_SetCooperativeLevel (ddrawsink->ddraw_object,
1294 NULL, DDSCL_NORMAL);
1295 if (hRes != DD_OK) {
1296 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1297 ("Failed to set the set the cooperative level error=%s",
1298 DDErrorString (hRes)), (NULL));
1302 /* setup the clipper object */
1303 hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
1304 &ddrawsink->clipper, NULL);
1306 if (hRes == DD_OK && ddrawsink->video_window)
1307 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1309 /* create our primary surface */
1310 if (!gst_directdraw_sink_check_primary_surface (ddrawsink))
1313 /* directdraw objects are setup */
1314 ddrawsink->setup = TRUE;
1320 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1326 DestroyWindow (hWnd);
1328 PostQuitMessage (0);
1332 return DefWindowProc (hWnd, message, wParam, lParam);
1336 gst_directdraw_sink_window_thread (GstDirectDrawSink * ddrawsink)
1341 memset (&WndClass, 0, sizeof (WNDCLASS));
1342 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1343 WndClass.hInstance = GetModuleHandle (NULL);
1344 WndClass.lpszClassName = "GStreamer-DirectDraw";
1345 WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
1346 WndClass.cbClsExtra = 0;
1347 WndClass.cbWndExtra = 0;
1348 WndClass.lpfnWndProc = WndProc;
1349 WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
1350 RegisterClass (&WndClass);
1352 ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
1353 "GStreamer-DirectDraw sink default window",
1354 WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
1355 WndClass.hInstance, NULL);
1356 if (ddrawsink->video_window == NULL)
1359 /* Set the clipper on that window */
1360 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1362 /* signal application we created a window */
1363 gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ddrawsink),
1364 (gulong) ddrawsink->video_window);
1366 ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1368 /* start message loop processing our default window messages */
1369 while (GetMessage (&msg, NULL, 0, 0) != FALSE) {
1370 TranslateMessage (&msg);
1371 DispatchMessage (&msg);
1374 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1375 "our window received WM_QUIT or error.");
1376 /* The window could have changed, if it is not ours anymore we don't
1377 * overwrite the current video window with NULL */
1378 if (ddrawsink->our_video_window) {
1379 GST_OBJECT_LOCK (ddrawsink);
1380 ddrawsink->video_window = NULL;
1381 GST_OBJECT_UNLOCK (ddrawsink);
1388 gst_directdraw_sink_create_default_window (GstDirectDrawSink * ddrawsink)
1390 ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1391 if (ddrawsink->window_created_signal == NULL)
1394 ddrawsink->window_thread = g_thread_create (
1395 (GThreadFunc) gst_directdraw_sink_window_thread, ddrawsink, TRUE, NULL);
1397 if (ddrawsink->window_thread == NULL)
1400 /* wait maximum 10 seconds for windows creating */
1401 if (WaitForSingleObject (ddrawsink->window_created_signal,
1402 10000) != WAIT_OBJECT_0)
1405 CloseHandle (ddrawsink->window_created_signal);
1409 CloseHandle (ddrawsink->window_created_signal);
1410 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1411 ("Error creating our default window"), (NULL));
1417 gst_directdraw_sink_check_primary_surface (GstDirectDrawSink * ddrawsink)
1420 DDSURFACEDESC2 dd_surface_desc;
1423 /* if our primary surface already exist, check if it's not lost */
1424 if (ddrawsink->primary_surface) {
1425 if (IDirectDrawSurface7_IsLost (ddrawsink->primary_surface) == DD_OK) {
1426 /* no problem with our primary surface */
1429 /* our primary surface was lost, try to restore it */
1430 if (IDirectDrawSurface7_Restore (ddrawsink->primary_surface) == DD_OK) {
1431 /* restore is done */
1432 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1433 "Our primary surface" " was restored after lost");
1436 /* failed to restore our primary surface,
1437 * probably because the display mode was changed.
1438 * Release this surface and recreate a new one.
1440 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1441 "Our primary surface"
1442 " was lost and display mode has changed. Destroy and recreate our surface.");
1443 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
1444 ddrawsink->primary_surface = NULL;
1446 /* also release offscreen surface */
1447 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1448 ddrawsink->offscreen_surface = NULL;
1453 /* create our primary surface */
1454 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1455 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1456 dd_surface_desc.dwFlags = DDSD_CAPS;
1457 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1458 sd = &dd_surface_desc;
1460 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1461 &ddrawsink->primary_surface, NULL);
1462 if (hres != DD_OK) {
1463 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1464 ("Failed to create our primary surface error=%s", DDErrorString (hres)),
1469 /* attach our clipper object to the new primary surface */
1470 if (ddrawsink->clipper) {
1471 hres = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
1472 ddrawsink->clipper);
1479 gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink * ddrawsink)
1481 DDSURFACEDESC2 dd_surface_desc;
1485 /* if our offscreen surface already exist, check if it's not lost */
1486 if (ddrawsink->offscreen_surface) {
1487 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK) {
1488 /* no problem with our offscreen surface */
1491 /* our offscreen surface was lost, try to restore it */
1492 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
1493 /* restore is done */
1494 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1495 "Our offscreen surface" " was restored after lost");
1498 /* failed to restore our offscreen surface,
1499 * probably because the display mode was changed.
1500 * Release this surface and recreate a new one.
1502 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1503 "Our offscreen surface"
1504 " was lost and display mode has changed. Destroy and recreate our surface.");
1505 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1506 ddrawsink->offscreen_surface = NULL;
1511 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1512 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1513 dd_surface_desc.dwFlags =
1514 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1515 dd_surface_desc.dwHeight = ddrawsink->video_height;
1516 dd_surface_desc.dwWidth = ddrawsink->video_width;
1517 memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
1518 sizeof (DDPIXELFORMAT));
1520 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1521 sd = &dd_surface_desc;
1523 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1524 &ddrawsink->offscreen_surface, NULL);
1525 if (hres != DD_OK) {
1526 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1527 "create_ddraw_surface:CreateSurface (offscreen surface for buffer_pool) failed %s",
1528 DDErrorString (hres));
1532 ddrawsink->must_recreate_offscreen = FALSE;
1538 gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1540 gint order = 0, binary;
1543 lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
1544 dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
1546 while (binary != 0) {
1547 if ((binary % 2) == 1)
1549 binary = binary >> 1;
1555 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1557 GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1558 GstCaps *format_caps = NULL;
1559 LPDDSURFACEDESC2 sd;
1561 if (!ddrawsink || !lpDDSurfaceDesc)
1562 return DDENUMRET_CANCEL;
1564 sd = (LPDDSURFACEDESC2) lpDDSurfaceDesc;
1565 if ((sd->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
1566 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1567 "Display mode found with DDSD_PIXELFORMAT not set");
1568 return DDENUMRET_OK;
1571 if ((sd->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1572 return DDENUMRET_OK;
1574 format_caps = gst_directdraw_sink_create_caps_from_surfacedesc (sd);
1577 gst_caps_append (ddrawsink->caps, format_caps);
1580 return DDENUMRET_OK;
1584 gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc)
1586 GstCaps *caps = NULL;
1587 gint endianness = G_LITTLE_ENDIAN;
1590 if ((desc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1593 depth = gst_directdraw_sink_get_depth (&desc->ddpfPixelFormat);
1595 if (desc->ddpfPixelFormat.dwRGBBitCount == 24 ||
1596 desc->ddpfPixelFormat.dwRGBBitCount == 32) {
1597 /* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
1598 endianness = G_BIG_ENDIAN;
1599 desc->ddpfPixelFormat.dwRBitMask =
1600 GUINT32_TO_BE (desc->ddpfPixelFormat.dwRBitMask);
1601 desc->ddpfPixelFormat.dwGBitMask =
1602 GUINT32_TO_BE (desc->ddpfPixelFormat.dwGBitMask);
1603 desc->ddpfPixelFormat.dwBBitMask =
1604 GUINT32_TO_BE (desc->ddpfPixelFormat.dwBBitMask);
1605 if (desc->ddpfPixelFormat.dwRGBBitCount == 24) {
1606 desc->ddpfPixelFormat.dwRBitMask >>= 8;
1607 desc->ddpfPixelFormat.dwGBitMask >>= 8;
1608 desc->ddpfPixelFormat.dwBBitMask >>= 8;
1612 caps = gst_caps_new_simple ("video/x-raw-rgb",
1613 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1614 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1615 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
1616 "bpp", G_TYPE_INT, desc->ddpfPixelFormat.dwRGBBitCount,
1617 "depth", G_TYPE_INT, depth,
1618 "endianness", G_TYPE_INT, endianness,
1619 "red_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwRBitMask,
1620 "green_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwGBitMask,
1621 "blue_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwBBitMask, NULL);
1627 gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1629 HRESULT hRes = S_OK;
1630 DDCAPS ddcaps_hardware;
1631 DDCAPS ddcaps_emulation;
1632 GstCaps *format_caps = NULL;
1634 ddrawsink->caps = gst_caps_new_empty ();
1635 if (!ddrawsink->caps)
1638 /* get hardware caps */
1639 ddcaps_hardware.dwSize = sizeof (DDCAPS);
1640 ddcaps_emulation.dwSize = sizeof (DDCAPS);
1641 IDirectDraw7_GetCaps (ddrawsink->ddraw_object, &ddcaps_hardware,
1644 /* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw
1645 * emulation layer can do it */
1646 if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
1647 DDSURFACEDESC2 surface_desc;
1650 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1651 "hardware doesn't support blit from one colorspace to another one. "
1652 "so we will create a caps with only the current display mode");
1654 /* save blit caps */
1655 ddrawsink->can_blit_between_colorspace = FALSE;
1657 surface_desc.dwSize = sizeof (surface_desc);
1660 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
1661 (DDSURFACEDESC *) sd);
1662 if (hRes != DD_OK) {
1663 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1664 ("Error getting the current display mode error=%s",
1665 DDErrorString (hRes)), (NULL));
1670 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
1672 gst_caps_append (ddrawsink->caps, format_caps);
1675 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1676 gst_caps_to_string (ddrawsink->caps));
1677 return ddrawsink->caps;
1680 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1681 "the hardware can blit from one colorspace to another, "
1682 "then enumerate the colorspace supported by the hardware");
1684 /* save blit caps */
1685 ddrawsink->can_blit_between_colorspace = TRUE;
1687 /* enumerate display modes exposed by directdraw object
1688 to know supported RGB modes */
1690 IDirectDraw7_EnumDisplayModes (ddrawsink->ddraw_object,
1691 DDEDM_REFRESHRATES, NULL, ddrawsink, EnumModesCallback2);
1692 if (hRes != DD_OK) {
1693 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1694 ("Error enumerating display modes error=%s", DDErrorString (hRes)),
1700 if (gst_caps_is_empty (ddrawsink->caps)) {
1701 gst_caps_unref (ddrawsink->caps);
1702 ddrawsink->caps = NULL;
1703 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1704 ("No supported caps found."), (NULL));
1708 /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1709 * gst_caps_to_string (ddrawsink->caps)); */
1711 return ddrawsink->caps;
1714 /* Creates miniobject and our internal surface */
1715 static GstDDrawSurface *
1716 gst_directdraw_sink_surface_create (GstDirectDrawSink * ddrawsink,
1717 GstCaps * caps, size_t size)
1719 GstDDrawSurface *surface = NULL;
1720 GstStructure *structure = NULL;
1726 DDSURFACEDESC2 surf_desc, surf_lock_desc;
1728 g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1730 /*init structures */
1731 memset (&surf_desc, 0, sizeof (surf_desc));
1732 memset (&surf_lock_desc, 0, sizeof (surf_desc));
1733 surf_desc.dwSize = sizeof (surf_desc);
1734 surf_lock_desc.dwSize = sizeof (surf_lock_desc);
1736 /*create miniobject and initialize it */
1737 surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1738 surface->locked = FALSE;
1740 structure = gst_caps_get_structure (caps, 0);
1741 if (!gst_structure_get_int (structure, "width", &surface->width) ||
1742 !gst_structure_get_int (structure, "height", &surface->height)) {
1743 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1744 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
1747 pitch = GST_ROUND_UP_8 (size / surface->height);
1748 if (!gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
1749 &surface->dd_pixel_format)) {
1750 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1751 "failed getting pixel format from caps %" GST_PTR_FORMAT, caps);
1754 /* disable return of directdraw surface to buffer alloc because actually I
1755 * have no solution to handle display mode changes. The problem is that when
1756 * the display mode is changed surface's memory is freed then the upstream
1757 * filter would crash trying to write to this memory. Directdraw has a system
1758 * lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
1759 * when a surface memory is locked but we need to disable this lock to return
1760 * multiple buffers (surfaces) and do not lock directdraw API calls.
1763 /* if (ddrawsink->ddraw_object) {*/
1764 /* Creating an internal surface which will be used as GstBuffer, we used
1765 the detected pixel format and video dimensions */
1767 surf_desc.ddsCaps.dwCaps =
1768 DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1770 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1771 surf_desc.dwHeight = surface->height;
1772 surf_desc.dwWidth = surface->width;
1773 memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1774 sizeof (DDPIXELFORMAT));
1776 hRes = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1777 &surface->surface, NULL);
1778 if (hRes != DD_OK) {
1779 goto surface_pitch_bad;
1782 /* Locking the surface to acquire the memory pointer.
1783 Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
1784 if directdraw api is used while a buffer is lock */
1786 hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1787 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1788 if (hRes == DDERR_SURFACELOST) {
1789 IDirectDrawSurface7_Restore (surface->surface);
1792 surface->locked = TRUE;
1794 if (surf_lock_desc.lPitch != pitch) {
1795 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1796 "DDraw stride/pitch %ld isn't as expected value %d, let's continue allocating a system memory buffer.",
1797 surf_lock_desc.lPitch, pitch);
1799 /*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
1800 hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
1801 goto surface_pitch_bad;
1803 GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
1804 GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
1805 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1806 "allocating a surface of %d bytes (stride=%ld)\n", size,
1807 surf_lock_desc.lPitch);
1811 GST_BUFFER (surface)->malloc_data = g_malloc (size);
1812 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
1813 GST_BUFFER_SIZE (surface) = size;
1814 surface->surface = NULL;
1815 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1816 "allocating a system memory buffer of %d bytes", size);
1820 /* Keep a ref to our sink */
1821 surface->ddrawsink = gst_object_ref (ddrawsink);
1826 /* We are called from the finalize method of miniobject, the object will be
1827 * destroyed so we just have to clean our internal stuff */
1829 gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
1830 GstDDrawSurface * surface)
1832 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
1834 /* Release our internal surface */
1835 if (surface->surface) {
1836 if (surface->locked) {
1837 IDirectDrawSurface7_Unlock (surface->surface, NULL);
1838 surface->locked = FALSE;
1840 IDirectDrawSurface7_Release (surface->surface);
1841 surface->surface = NULL;
1844 if (GST_BUFFER (surface)->malloc_data) {
1845 g_free (GST_BUFFER (surface)->malloc_data);
1846 GST_BUFFER (surface)->malloc_data = NULL;
1849 if (!surface->ddrawsink) {
1853 /* Release the ref to our sink */
1854 surface->ddrawsink = NULL;
1855 gst_object_unref (ddrawsink);
1860 GST_WARNING ("no sink found in surface");
1865 gst_directdraw_sink_surface_check (GstDirectDrawSink * ddrawsink,
1866 GstDDrawSurface * surface)
1868 if (!surface->surface)
1869 return TRUE; /* system memory buffer */
1871 if (IDirectDrawSurface7_IsLost (surface->surface) == DD_OK) {
1872 /* no problem with this surface */
1875 /* this surface was lost, try to restore it */
1876 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
1877 /* restore is done */
1878 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink, "A surface from our"
1879 " bufferpool was restored after lost");
1888 gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
1890 g_mutex_lock (ddrawsink->pool_lock);
1891 while (ddrawsink->buffer_pool) {
1892 GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
1894 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
1895 ddrawsink->buffer_pool);
1896 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
1897 gst_buffer_unref (surface);
1899 g_mutex_unlock (ddrawsink->pool_lock);
1903 gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink)
1905 /* Post quit message and wait for our event window thread */
1906 if (ddrawsink->video_window && ddrawsink->our_video_window)
1907 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
1909 if (ddrawsink->window_thread) {
1910 g_thread_join (ddrawsink->window_thread);
1911 ddrawsink->window_thread = NULL;
1914 if (ddrawsink->buffer_pool) {
1915 gst_directdraw_sink_bufferpool_clear (ddrawsink);
1916 ddrawsink->buffer_pool = NULL;
1919 if (ddrawsink->offscreen_surface) {
1920 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1921 ddrawsink->offscreen_surface = NULL;
1924 if (ddrawsink->clipper) {
1925 IDirectDrawClipper_Release (ddrawsink->clipper);
1926 ddrawsink->clipper = NULL;
1929 if (ddrawsink->primary_surface) {
1930 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
1931 ddrawsink->primary_surface = NULL;
1934 if (ddrawsink->ddraw_object) {
1935 IDirectDraw7_Release (ddrawsink->ddraw_object);
1936 ddrawsink->ddraw_object = NULL;
1939 if (ddrawsink->last_buffer) {
1940 gst_buffer_unref (ddrawsink->last_buffer);
1941 ddrawsink->last_buffer = NULL;
1944 ddrawsink->setup = FALSE;