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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, 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 -v videotestsrc ! directdrawsink
38 * ]| a simple pipeline to test the sink
46 #include "gstdirectdrawsink.h"
47 #include <gst/video/video.h>
49 GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
50 #define GST_CAT_DEFAULT directdrawsink_debug
52 static void gst_directdraw_sink_init_interfaces (GType type);
54 GST_BOILERPLATE_FULL (GstDirectDrawSink, gst_directdraw_sink, GstVideoSink,
55 GST_TYPE_VIDEO_SINK, gst_directdraw_sink_init_interfaces);
57 static void gst_directdraw_sink_finalize (GObject * object);
58 static void gst_directdraw_sink_set_property (GObject * object,
59 guint prop_id, const GValue * value, GParamSpec * pspec);
60 static void gst_directdraw_sink_get_property (GObject * object,
61 guint prop_id, GValue * value, GParamSpec * pspec);
62 static GstCaps *gst_directdraw_sink_get_caps (GstBaseSink * bsink);
63 static gboolean gst_directdraw_sink_set_caps (GstBaseSink * bsink,
65 static GstStateChangeReturn gst_directdraw_sink_change_state (GstElement *
66 element, GstStateChange transition);
67 static GstFlowReturn gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink,
68 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
69 static void gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
70 GstClockTime * start, GstClockTime * end);
71 static GstFlowReturn gst_directdraw_sink_show_frame (GstBaseSink * bsink,
75 static gboolean gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink);
76 static gboolean gst_directdraw_sink_create_default_window (GstDirectDrawSink *
78 static gboolean gst_directdraw_sink_check_primary_surface (GstDirectDrawSink *
80 static gboolean gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink *
82 static GstCaps *gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink *
85 * gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc);
86 static void gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink);
87 static void gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink *
89 static int gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat);
90 static gboolean gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink *
91 ddrawsink, GstCaps * caps, DDPIXELFORMAT * pPixelFormat);
92 static void gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink,
93 RECT src, RECT dst, RECT * result);
94 static const char *DDErrorString (HRESULT hr);
96 /* surfaces management functions */
97 static void gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
98 GstDDrawSurface * surface);
99 static GstDDrawSurface *gst_directdraw_sink_surface_create (GstDirectDrawSink *
100 ddrawsink, GstCaps * caps, size_t size);
101 static gboolean gst_directdraw_sink_surface_check (GstDirectDrawSink *
102 ddrawsink, GstDDrawSurface * surface);
104 static GstStaticPadTemplate directdrawsink_sink_factory =
105 GST_STATIC_PAD_TEMPLATE ("sink",
108 GST_STATIC_CAPS ("video/x-raw-rgb, "
109 "framerate = (fraction) [ 0, MAX ], "
110 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
116 PROP_KEEP_ASPECT_RATIO
119 /* XOverlay interface implementation */
121 gst_directdraw_sink_interface_supported (GstImplementsInterface * iface,
124 if (type == GST_TYPE_X_OVERLAY)
126 else if (type == GST_TYPE_NAVIGATION)
132 gst_directdraw_sink_interface_init (GstImplementsInterfaceClass * klass)
134 klass->supported = gst_directdraw_sink_interface_supported;
138 gst_directdraw_sink_set_window_handle (GstXOverlay * overlay,
139 guintptr window_handle)
141 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
143 GST_OBJECT_LOCK (ddrawsink);
144 /* check if we are already using this window id */
145 if (ddrawsink->video_window == (HWND) window_handle) {
146 GST_OBJECT_UNLOCK (ddrawsink);
153 /* If we had an internal window, close it first */
154 if (ddrawsink->video_window && ddrawsink->our_video_window) {
155 /* Trick to let the event thread know that it has to die silently */
156 ddrawsink->our_video_window = FALSE;
157 /* Post quit message and wait for our event window thread */
158 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
161 ddrawsink->video_window = (HWND) window_handle;
162 ddrawsink->our_video_window = FALSE;
163 if (ddrawsink->setup) {
164 /* update the clipper object with the new window */
165 hres = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
166 ddrawsink->video_window);
169 /* FIXME: Handle the case where window_handle is 0 and we want the sink to
170 * create a new window when playback was already started (after set_caps) */
171 GST_OBJECT_UNLOCK (ddrawsink);
175 gst_directdraw_sink_expose (GstXOverlay * overlay)
177 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
179 gst_directdraw_sink_show_frame (GST_BASE_SINK (ddrawsink), NULL);
183 gst_directdraw_sink_xoverlay_interface_init (GstXOverlayClass * iface)
185 iface->set_window_handle = gst_directdraw_sink_set_window_handle;
186 iface->expose = gst_directdraw_sink_expose;
190 gst_directdraw_sink_navigation_send_event (GstNavigation * navigation,
191 GstStructure * structure)
193 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (navigation);
195 GstVideoRectangle src, dst, result;
196 gdouble x, y, old_x, old_y, xscale = 1.0, yscale=1.0;
199 src.w = GST_VIDEO_SINK_WIDTH (ddrawsink);
200 src.h = GST_VIDEO_SINK_HEIGHT (ddrawsink);
201 dst.w = ddrawsink->out_width;
202 dst.h = ddrawsink->out_height;
204 event = gst_event_new_navigation (structure);
206 if (ddrawsink->keep_aspect_ratio) {
207 gst_video_sink_center_rect (src, dst, &result, TRUE);
215 /* We calculate scaling using the original video frames geometry to include
216 pixel aspect ratio scaling. */
217 xscale = (gdouble) ddrawsink->video_width / result.w;
218 yscale = (gdouble) ddrawsink->video_height / result.h;
220 /* Converting pointer coordinates to the non scaled geometry */
221 if (gst_structure_get_double (structure, "pointer_x", &old_x)) {
223 x = MIN (x, result.x + result.w);
224 x = MAX (x - result.x, 0);
225 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
226 (gdouble) x * xscale, NULL);
227 GST_DEBUG_OBJECT (ddrawsink,
228 "translated navigation event x coordinate from %f to %f", old_x, x);
230 if (gst_structure_get_double (structure, "pointer_y", &old_y)) {
232 y = MIN (y, result.y + result.h);
233 y = MAX (y - result.y, 0);
234 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
235 (gdouble) y * yscale, NULL);
236 GST_DEBUG_OBJECT (ddrawsink,
237 "translated navigation event x coordinate from %f to %f", old_y, y);
240 pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (ddrawsink));
242 if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
243 gst_pad_send_event (pad, event);
245 gst_object_unref (pad);
250 gst_directdraw_sink_navigation_interface_init (GstNavigationInterface * iface)
252 iface->send_event = gst_directdraw_sink_navigation_send_event;
256 gst_directdraw_sink_init_interfaces (GType type)
258 static const GInterfaceInfo iface_info = {
259 (GInterfaceInitFunc) gst_directdraw_sink_interface_init,
264 static const GInterfaceInfo xoverlay_info = {
265 (GInterfaceInitFunc) gst_directdraw_sink_xoverlay_interface_init,
270 static const GInterfaceInfo navigation_info = {
271 (GInterfaceInitFunc) gst_directdraw_sink_navigation_interface_init,
276 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
278 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
279 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
282 /* Subclass of GstBuffer which manages buffer_pool surfaces lifetime */
283 static void gst_ddrawsurface_finalize (GstMiniObject * mini_object);
284 static GstBufferClass *ddrawsurface_parent_class = NULL;
287 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
289 surface->surface = NULL;
292 surface->ddrawsink = NULL;
293 surface->locked = FALSE;
294 surface->system_memory = FALSE;
295 memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
299 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
301 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
303 ddrawsurface_parent_class = g_type_class_peek_parent (g_class);
305 mini_object_class->finalize = GST_DEBUG_FUNCPTR (gst_ddrawsurface_finalize);
309 gst_ddrawsurface_get_type (void)
311 static GType _gst_ddrawsurface_type;
313 if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
314 static const GTypeInfo ddrawsurface_info = {
315 sizeof (GstBufferClass),
318 gst_ddrawsurface_class_init,
321 sizeof (GstDDrawSurface),
323 (GInstanceInitFunc) gst_ddrawsurface_init,
326 _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
327 "GstDDrawSurface", &ddrawsurface_info, 0);
329 return _gst_ddrawsurface_type;
333 gst_ddrawsurface_finalize (GstMiniObject * mini_object)
335 GstDirectDrawSink *ddrawsink = NULL;
336 GstDDrawSurface *surface;
338 surface = (GstDDrawSurface *) mini_object;
340 ddrawsink = surface->ddrawsink;
344 /* If our geometry changed we can't reuse that image. */
345 if ((surface->width != ddrawsink->video_width) ||
346 (surface->height != ddrawsink->video_height) ||
347 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
348 sizeof (DDPIXELFORMAT)) != 0 ||
349 !gst_directdraw_sink_surface_check (ddrawsink, surface))
351 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
352 "destroy image as its size changed %dx%d vs current %dx%d",
353 surface->width, surface->height, ddrawsink->video_width,
354 ddrawsink->video_height);
355 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
356 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
358 /* In that case we can reuse the image and add it to our image pool. */
359 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
360 "recycling image in pool");
362 /* need to increment the refcount again to recycle */
363 gst_buffer_ref (GST_BUFFER (surface));
365 g_mutex_lock (ddrawsink->pool_lock);
366 ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
367 g_mutex_unlock (ddrawsink->pool_lock);
373 GST_CAT_WARNING (directdrawsink_debug, "no sink found");
374 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
378 /************************************************************************/
379 /* Directdraw sink functions */
380 /************************************************************************/
382 gst_directdraw_sink_base_init (gpointer g_class)
384 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
386 gst_element_class_set_static_metadata (element_class,
387 "Direct Draw Video Sink", "Sink/Video",
388 "Output to a video card via Direct Draw",
389 "Sebastien Moutte <sebastien@moutte.net>");
390 gst_element_class_add_pad_template (element_class,
391 gst_static_pad_template_get (&directdrawsink_sink_factory));
395 gst_directdraw_sink_class_init (GstDirectDrawSinkClass * klass)
397 GObjectClass *gobject_class;
398 GstElementClass *gstelement_class;
399 GstBaseSinkClass *gstbasesink_class;
401 gobject_class = (GObjectClass *) klass;
402 gstbasesink_class = (GstBaseSinkClass *) klass;
403 gstelement_class = (GstElementClass *) klass;
405 GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
408 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdraw_sink_finalize);
409 gobject_class->get_property =
410 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_property);
411 gobject_class->set_property =
412 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_property);
413 gstelement_class->change_state =
414 GST_DEBUG_FUNCPTR (gst_directdraw_sink_change_state);
415 gstbasesink_class->get_caps =
416 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_caps);
417 gstbasesink_class->set_caps =
418 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_caps);
419 gstbasesink_class->preroll =
420 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
421 gstbasesink_class->render =
422 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
423 gstbasesink_class->get_times =
424 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_times);
425 gstbasesink_class->buffer_alloc =
426 GST_DEBUG_FUNCPTR (gst_directdraw_sink_buffer_alloc);
428 /* install properties */
429 /* setup aspect ratio mode */
430 g_object_class_install_property (G_OBJECT_CLASS (klass),
431 PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("force-aspect-ratio",
432 "Force aspect ratio",
433 "When enabled, scaling will respect original aspect ratio", TRUE,
438 gst_directdraw_sink_set_property (GObject * object, guint prop_id,
439 const GValue * value, GParamSpec * pspec)
441 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
444 case PROP_KEEP_ASPECT_RATIO:
445 ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
448 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
454 gst_directdraw_sink_get_property (GObject * object, guint prop_id,
455 GValue * value, GParamSpec * pspec)
457 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
460 case PROP_KEEP_ASPECT_RATIO:
461 g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
470 gst_directdraw_sink_finalize (GObject * object)
472 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
474 if (ddrawsink->pool_lock) {
475 g_mutex_free (ddrawsink->pool_lock);
476 ddrawsink->pool_lock = NULL;
478 if (ddrawsink->caps) {
479 gst_caps_unref (ddrawsink->caps);
480 ddrawsink->caps = NULL;
482 if (ddrawsink->setup) {
483 gst_directdraw_sink_cleanup (ddrawsink);
486 G_OBJECT_CLASS (parent_class)->finalize (object);
490 gst_directdraw_sink_init (GstDirectDrawSink * ddrawsink,
491 GstDirectDrawSinkClass * g_class)
493 /*init members variables */
494 ddrawsink->ddraw_object = NULL;
495 ddrawsink->primary_surface = NULL;
496 ddrawsink->offscreen_surface = NULL;
497 ddrawsink->clipper = NULL;
498 ddrawsink->video_window = NULL;
499 ddrawsink->our_video_window = TRUE;
500 ddrawsink->last_buffer = NULL;
501 ddrawsink->caps = NULL;
502 ddrawsink->window_thread = NULL;
503 ddrawsink->setup = FALSE;
504 ddrawsink->buffer_pool = NULL;
505 ddrawsink->keep_aspect_ratio = FALSE;
506 ddrawsink->pool_lock = g_mutex_new ();
507 ddrawsink->can_blit_between_colorspace = TRUE;
508 ddrawsink->must_recreate_offscreen = FALSE;
509 memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
511 /*video default values */
512 ddrawsink->video_height = 0;
513 ddrawsink->video_width = 0;
514 ddrawsink->fps_n = 0;
515 ddrawsink->fps_d = 0;
519 gst_directdraw_sink_get_caps (GstBaseSink * bsink)
521 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
522 GstCaps *caps = NULL;
524 if (!ddrawsink->setup) {
525 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
527 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
528 "getcaps called and we are not setup yet, " "returning template %"
529 GST_PTR_FORMAT, caps);
531 caps = gst_caps_ref (ddrawsink->caps);
538 gst_directdraw_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
540 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
541 GstStructure *structure = NULL;
546 structure = gst_caps_get_structure (caps, 0);
550 if (!gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d)) {
555 ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
556 ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
557 fps = gst_structure_get_value (structure, "framerate");
558 ret &= (fps != NULL);
560 gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
561 &ddrawsink->dd_pixel_format);
563 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
564 ("Failed to get caps properties from caps"), (NULL));
567 GST_VIDEO_SINK_WIDTH (ddrawsink) = ddrawsink->video_width * par_n / par_d;
568 GST_VIDEO_SINK_HEIGHT (ddrawsink) = ddrawsink->video_height;
570 ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
571 ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
573 /* Notify application to set window id now */
574 if (!ddrawsink->video_window) {
575 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ddrawsink));
578 /* If we still don't have a window at that stage we create our own */
579 if (!ddrawsink->video_window) {
580 gst_directdraw_sink_create_default_window (ddrawsink);
583 /* if we are rendering to our own window, resize it to video size */
584 if (ddrawsink->video_window && ddrawsink->our_video_window) {
585 SetWindowPos (ddrawsink->video_window, NULL,
587 GST_VIDEO_SINK_WIDTH (ddrawsink) +
588 (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
589 GST_VIDEO_SINK_HEIGHT (ddrawsink) + GetSystemMetrics (SM_CYCAPTION) +
590 (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
593 /* release the surface, we have to recreate it! */
594 if (ddrawsink->offscreen_surface) {
595 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
596 ddrawsink->offscreen_surface = NULL;
599 /* create an offscreen surface with the caps */
600 ret = gst_directdraw_sink_check_offscreen_surface (ddrawsink);
602 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
603 ("Can't create a directdraw offscreen surface with the input caps"),
610 static GstStateChangeReturn
611 gst_directdraw_sink_change_state (GstElement * element,
612 GstStateChange transition)
614 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (element);
615 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
617 switch (transition) {
618 case GST_STATE_CHANGE_NULL_TO_READY:
619 if (!gst_directdraw_sink_setup_ddraw (ddrawsink)) {
620 ret = GST_STATE_CHANGE_FAILURE;
624 if (!(ddrawsink->caps = gst_directdraw_sink_get_ddrawcaps (ddrawsink))) {
625 ret = GST_STATE_CHANGE_FAILURE;
633 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
635 switch (transition) {
636 case GST_STATE_CHANGE_PAUSED_TO_READY:
637 ddrawsink->fps_n = 0;
638 ddrawsink->fps_d = 1;
639 ddrawsink->video_width = 0;
640 ddrawsink->video_height = 0;
641 if (ddrawsink->buffer_pool)
642 gst_directdraw_sink_bufferpool_clear (ddrawsink);
644 case GST_STATE_CHANGE_READY_TO_NULL:
645 if (ddrawsink->setup)
646 gst_directdraw_sink_cleanup (ddrawsink);
657 gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
658 guint size, GstCaps * caps, GstBuffer ** buf)
660 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
661 GstStructure *structure;
663 GstDDrawSurface *surface = NULL;
664 GstFlowReturn ret = GST_FLOW_OK;
665 GstCaps *buffer_caps = caps;
666 gboolean buffercaps_unref = FALSE;
668 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
669 "a buffer of %u bytes was requested", size);
671 structure = gst_caps_get_structure (caps, 0);
672 if (!gst_structure_get_int (structure, "width", &width) ||
673 !gst_structure_get_int (structure, "height", &height)) {
674 GST_WARNING_OBJECT (ddrawsink, "invalid caps for buffer allocation %"
675 GST_PTR_FORMAT, caps);
676 return GST_FLOW_UNEXPECTED;
679 g_mutex_lock (ddrawsink->pool_lock);
681 /* Inspect our buffer pool */
682 while (ddrawsink->buffer_pool) {
683 surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
685 /* Removing from the pool */
686 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
687 ddrawsink->buffer_pool);
689 /* If the surface is invalid for our need, destroy */
690 if ((surface->width != width) ||
691 (surface->height != height) ||
692 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
693 sizeof (DDPIXELFORMAT)) ||
694 !gst_directdraw_sink_surface_check (ddrawsink, surface))
696 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
697 gst_buffer_unref (GST_BUFFER_CAST (surface));
700 /* We found a suitable surface */
706 if (!ddrawsink->can_blit_between_colorspace) {
707 /* Hardware doesn't support blit from one colorspace to another.
708 * Check if the colorspace of the current display mode has changed since
709 * the last negociation. If it's the case, we will have to renegociate
713 DDSURFACEDESC2 surface_desc;
716 if (!gst_structure_get_int (structure, "depth", (gint *) & depth)) {
717 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
718 "Can't get depth from buffer_alloc caps");
719 return GST_FLOW_ERROR;
721 surface_desc.dwSize = sizeof (surface_desc);
724 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
725 (DDSURFACEDESC *) sd);
727 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
728 "Can't get current display mode (error=%ld)", (glong) hres);
729 return GST_FLOW_ERROR;
732 if (depth != gst_directdraw_sink_get_depth (&surface_desc.ddpfPixelFormat)) {
733 GstCaps *copy_caps = NULL;
734 GstStructure *copy_structure = NULL;
735 GstCaps *display_caps = NULL;
736 GstStructure *display_structure = NULL;
738 /* make a copy of the original caps */
739 copy_caps = gst_caps_copy (caps);
740 copy_structure = gst_caps_get_structure (copy_caps, 0);
743 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
745 display_structure = gst_caps_get_structure (display_caps, 0);
746 if (display_structure) {
747 gint bpp, endianness, red_mask, green_mask, blue_mask;
749 /* get new display mode properties */
750 gst_structure_get_int (display_structure, "depth", (gint *) & depth);
751 gst_structure_get_int (display_structure, "bpp", &bpp);
752 gst_structure_get_int (display_structure, "endianness", &endianness);
753 gst_structure_get_int (display_structure, "red_mask", &red_mask);
754 gst_structure_get_int (display_structure, "green_mask", &green_mask);
755 gst_structure_get_int (display_structure, "blue_mask", &blue_mask);
757 /* apply the new display mode changes to the previous caps */
758 gst_structure_set (copy_structure,
759 "bpp", G_TYPE_INT, bpp,
760 "depth", G_TYPE_INT, depth,
761 "endianness", G_TYPE_INT, endianness,
762 "red_mask", G_TYPE_INT, red_mask,
763 "green_mask", G_TYPE_INT, green_mask,
764 "blue_mask", G_TYPE_INT, blue_mask, NULL);
766 if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ddrawsink),
768 buffer_caps = copy_caps;
769 buffercaps_unref = TRUE;
770 /* update buffer size needed to store video frames according to new caps */
771 size = width * height * (bpp / 8);
773 /* update our member pixel format */
774 gst_ddrawvideosink_get_format_from_caps (ddrawsink, buffer_caps,
775 &ddrawsink->dd_pixel_format);
776 ddrawsink->must_recreate_offscreen = TRUE;
778 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
779 " desired caps %s \n\n new caps %s", gst_caps_to_string (caps),
780 gst_caps_to_string (buffer_caps));
782 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
783 "peer refused caps re-negociation "
784 "and we can't render with the current caps.");
785 ret = GST_FLOW_ERROR;
788 gst_caps_unref (display_caps);
791 if (!buffercaps_unref)
792 gst_caps_unref (copy_caps);
796 /* We haven't found anything, creating a new one */
798 surface = gst_directdraw_sink_surface_create (ddrawsink, buffer_caps, size);
801 /* Now we should have a surface, set appropriate caps on it */
803 GST_BUFFER_FLAGS (GST_BUFFER (surface)) = 0;
804 gst_buffer_set_caps (GST_BUFFER (surface), buffer_caps);
807 g_mutex_unlock (ddrawsink->pool_lock);
809 *buf = GST_BUFFER (surface);
811 if (buffercaps_unref)
812 gst_caps_unref (buffer_caps);
818 gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect)
820 RECT win_rect, fill_rect;
824 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
826 /* Get the target window rect */
829 ClientToScreen (ddrawsink->video_window, &win_point);
830 GetClientRect (ddrawsink->video_window, &win_rect);
831 OffsetRect (&win_rect, win_point.x, win_point.y);
833 /* We acquire a drawing context */
834 if ((hdc = GetDC (ddrawsink->video_window))) {
835 HBRUSH brush = CreateSolidBrush (RGB (0, 0, 0));
837 /* arrange for logical coordinates that match screen coordinates */
838 SetWindowOrgEx (hdc, win_point.x, win_point.y, NULL);
840 if (dst_rect.left > win_rect.left) {
841 fill_rect.left = win_rect.left;
842 fill_rect.top = win_rect.top;
843 fill_rect.bottom = win_rect.bottom;
844 fill_rect.right = dst_rect.left;
845 FillRect (hdc, &fill_rect, brush);
848 if (dst_rect.right < win_rect.right) {
849 fill_rect.top = win_rect.top;
850 fill_rect.left = dst_rect.right;
851 fill_rect.bottom = win_rect.bottom;
852 fill_rect.right = win_rect.right;
853 FillRect (hdc, &fill_rect, brush);
856 if (dst_rect.top > win_rect.top) {
857 fill_rect.top = win_rect.top;
858 fill_rect.left = win_rect.left;
859 fill_rect.right = win_rect.right;
860 fill_rect.bottom = dst_rect.top;
861 FillRect (hdc, &fill_rect, brush);
864 if (dst_rect.bottom < win_rect.bottom) {
865 fill_rect.top = dst_rect.bottom;
866 fill_rect.left = win_rect.left;
867 fill_rect.right = win_rect.right;
868 fill_rect.bottom = win_rect.bottom;
869 FillRect (hdc, &fill_rect, brush);
871 DeleteObject (brush);
872 ReleaseDC (ddrawsink->video_window, hdc);
877 gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
879 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
881 RECT destsurf_rect, src_rect;
882 POINT dest_surf_point;
885 /* save a reference to the input buffer */
886 gst_buffer_ref (buf);
887 if (ddrawsink->last_buffer != NULL)
888 gst_buffer_unref (ddrawsink->last_buffer);
889 ddrawsink->last_buffer = buf;
891 /* use last buffer */
892 buf = ddrawsink->last_buffer;
896 GST_ERROR_OBJECT (ddrawsink, "No buffer to render.");
897 return GST_FLOW_ERROR;
898 } else if (!ddrawsink->video_window) {
899 GST_WARNING_OBJECT (ddrawsink, "No video window to render to.");
900 return GST_FLOW_ERROR;
903 /* get the video window position */
904 GST_OBJECT_LOCK (ddrawsink);
905 if (G_UNLIKELY (!ddrawsink->video_window)) {
906 GST_OBJECT_UNLOCK (ddrawsink);
907 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
908 "gst_directdraw_sink_show_frame our video window disappeared");
909 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, NOT_FOUND,
910 ("Output window was closed"), (NULL));
911 return GST_FLOW_ERROR;
913 dest_surf_point.x = 0;
914 dest_surf_point.y = 0;
915 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
916 GetClientRect (ddrawsink->video_window, &destsurf_rect);
917 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
919 /* Check to see if we have an area to draw to.
920 * When the window is minimized, it will trigger the
921 * "IDirectDrawSurface7_Blt (object's offscreen surface)" warning,
922 * with a msg that the rectangle is invalid */
923 if (destsurf_rect.right <= destsurf_rect.left ||
924 destsurf_rect.bottom <= destsurf_rect.top) {
925 GST_OBJECT_UNLOCK (ddrawsink);
926 GST_DEBUG_OBJECT (ddrawsink, "invalid rendering window rectangle "
927 "(%ld, %ld), (%ld, %ld)", destsurf_rect.left, destsurf_rect.top,
928 destsurf_rect.right, destsurf_rect.bottom);
932 if (ddrawsink->keep_aspect_ratio) {
933 /* center image to dest image keeping aspect ratio */
936 src_rect.bottom = GST_VIDEO_SINK_HEIGHT (ddrawsink);
937 src_rect.right = GST_VIDEO_SINK_WIDTH (ddrawsink);
938 gst_directdraw_sink_center_rect (ddrawsink, src_rect, destsurf_rect,
940 gst_directdraw_sink_draw_borders (ddrawsink, destsurf_rect);
942 GST_OBJECT_UNLOCK (ddrawsink);
944 if (ddrawsink->must_recreate_offscreen && ddrawsink->offscreen_surface) {
945 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
946 ddrawsink->offscreen_surface = NULL;
949 /* check for surfaces lost */
950 if (!gst_directdraw_sink_check_primary_surface (ddrawsink) ||
951 !gst_directdraw_sink_check_offscreen_surface (ddrawsink)) {
952 return GST_FLOW_ERROR;
955 if (!GST_IS_DDRAWSURFACE (buf) ||
956 ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
957 /* We are receiving a system memory buffer so we will copy
958 to the memory of our offscreen surface and next blit this surface
959 on the primary surface */
961 guint src_pitch, line;
962 DDSURFACEDESC2 surf_desc;
965 ZeroMemory (&surf_desc, sizeof (surf_desc));
966 surf_desc.dwSize = sizeof (surf_desc);
969 /* Lock the surface */
971 IDirectDrawSurface7_Lock (ddrawsink->offscreen_surface, NULL,
972 (DDSURFACEDESC *) sd, DDLOCK_WAIT, NULL);
974 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
975 "gst_directdraw_sink_show_frame failed locking surface %s",
976 DDErrorString (hRes));
978 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK)
981 return GST_FLOW_ERROR;
984 /* Write each line respecting the destination surface pitch */
985 data = surf_desc.lpSurface;
986 if (ddrawsink->video_height) {
987 src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
988 for (line = 0; line < surf_desc.dwHeight; line++) {
989 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
990 data += surf_desc.lPitch;
994 /* Unlock the surface */
995 hRes = IDirectDrawSurface7_Unlock (ddrawsink->offscreen_surface, NULL);
997 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
998 "gst_directdraw_sink_show_frame failed unlocking surface %s",
999 DDErrorString (hRes));
1000 return GST_FLOW_ERROR;
1003 /* blit to primary surface ( Blt will scale the video the dest rect surface
1005 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
1006 ddrawsink->offscreen_surface, NULL, DDBLT_WAIT, NULL);
1007 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
1008 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1009 "IDirectDrawSurface7_Blt (object's offscreen surface) " "returned %s",
1010 DDErrorString (hRes));
1013 /* We are receiving a directdraw surface (previously returned by our buffer
1014 * pool so we will simply blit it on the primary surface */
1015 GstDDrawSurface *surface = NULL;
1017 surface = GST_DDRAWSURFACE (buf);
1019 /* Unlocking surface before blit */
1020 IDirectDrawSurface7_Unlock (surface->surface, NULL);
1021 surface->locked = FALSE;
1023 /* blit to our primary surface */
1024 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
1025 surface->surface, NULL, DDBLT_WAIT, NULL);
1026 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
1027 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1028 "IDirectDrawSurface7_Blt (offscreen surface from buffer_alloc) "
1029 "returned %s", DDErrorString (hRes));
1037 gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1038 GstClockTime * start, GstClockTime * end)
1040 GstDirectDrawSink *ddrawsink;
1042 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1044 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1045 *start = GST_BUFFER_TIMESTAMP (buf);
1046 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1047 *end = *start + GST_BUFFER_DURATION (buf);
1049 if (ddrawsink->fps_n > 0) {
1050 *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1056 /* Utility functions */
1058 /* this function fill a DDPIXELFORMAT using Gstreamer caps */
1060 gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink * ddrawsink,
1061 GstCaps * caps, DDPIXELFORMAT * pPixelFormat)
1063 GstStructure *structure = NULL;
1064 gboolean ret = TRUE;
1067 g_return_val_if_fail (pPixelFormat, FALSE);
1068 g_return_val_if_fail (caps, FALSE);
1070 /* init structure */
1071 memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
1072 pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
1074 if (!(structure = gst_caps_get_structure (caps, 0))) {
1075 GST_CAT_ERROR_OBJECT (directdrawsink_debug, ddrawsink,
1076 "can't get structure pointer from caps");
1080 if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
1081 gint depth, bitcount, bitmask, endianness;
1083 pPixelFormat->dwFlags = DDPF_RGB;
1084 ret &= gst_structure_get_int (structure, "bpp", &bitcount);
1085 pPixelFormat->dwRGBBitCount = bitcount;
1086 ret &= gst_structure_get_int (structure, "depth", &depth);
1087 ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
1088 pPixelFormat->dwRBitMask = bitmask;
1089 ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
1090 pPixelFormat->dwGBitMask = bitmask;
1091 ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
1092 pPixelFormat->dwBBitMask = bitmask;
1094 gst_structure_get_int (structure, "endianness", &endianness);
1095 if (endianness == G_BIG_ENDIAN) {
1096 endianness = G_LITTLE_ENDIAN;
1097 pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
1098 pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
1099 pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
1101 } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
1104 pPixelFormat->dwFlags = DDPF_FOURCC;
1105 ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
1106 pPixelFormat->dwFourCC = fourcc;
1108 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1109 "unknown caps name received %" GST_PTR_FORMAT, caps);
1116 /* This function centers the RECT of source surface to
1117 a dest surface and set the result RECT into result */
1119 gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink, RECT src,
1120 RECT dst, RECT * result)
1122 gdouble src_ratio, dst_ratio;
1123 long src_width = src.right;
1124 long src_height = src.bottom;
1125 long dst_width = dst.right - dst.left;
1126 long dst_heigth = dst.bottom - dst.top;
1127 long result_width = 0, result_height = 0;
1129 g_return_if_fail (result != NULL);
1131 src_ratio = (gdouble) src_width / src_height;
1132 dst_ratio = (gdouble) dst_width / dst_heigth;
1134 if (src_ratio > dst_ratio) {
1136 result_height = (long) (dst_width / src_ratio);
1138 result->left = dst.left;
1139 result->right = dst.right;
1140 result->top = dst.top + (dst_heigth - result_height) / 2;
1141 result->bottom = result->top + result_height;
1143 } else if (src_ratio < dst_ratio) {
1145 result_width = (long) (dst_heigth * src_ratio);
1147 result->top = dst.top;
1148 result->bottom = dst.bottom;
1149 result->left = dst.left + (dst_width - result_width) / 2;
1150 result->right = result->left + result_width;
1154 memcpy (result, &dst, sizeof (RECT));
1157 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1158 "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
1159 src_width, src_height, dst_width, dst_heigth,
1160 result->right - result->left, result->bottom - result->top, result->left,
1165 * Get DirectDraw error message.
1167 * Returns: Text representation of the error.
1170 DDErrorString (HRESULT hr)
1173 case DDERR_ALREADYINITIALIZED:
1174 return "DDERR_ALREADYINITIALIZED";
1175 case DDERR_CANNOTATTACHSURFACE:
1176 return "DDERR_CANNOTATTACHSURFACE";
1177 case DDERR_CANNOTDETACHSURFACE:
1178 return "DDERR_CANNOTDETACHSURFACE";
1179 case DDERR_CURRENTLYNOTAVAIL:
1180 return "DDERR_CURRENTLYNOTAVAIL";
1181 case DDERR_EXCEPTION:
1182 return "DDERR_EXCEPTION";
1184 return "DDERR_GENERIC";
1185 case DDERR_HEIGHTALIGN:
1186 return "DDERR_HEIGHTALIGN";
1187 case DDERR_INCOMPATIBLEPRIMARY:
1188 return "DDERR_INCOMPATIBLEPRIMARY";
1189 case DDERR_INVALIDCAPS:
1190 return "DDERR_INVALIDCAPS";
1191 case DDERR_INVALIDCLIPLIST:
1192 return "DDERR_INVALIDCLIPLIST";
1193 case DDERR_INVALIDMODE:
1194 return "DDERR_INVALIDMODE";
1195 case DDERR_INVALIDOBJECT:
1196 return "DDERR_INVALIDOBJECT";
1197 case DDERR_INVALIDPARAMS:
1198 return "DDERR_INVALIDPARAMS";
1199 case DDERR_INVALIDPIXELFORMAT:
1200 return "DDERR_INVALIDPIXELFORMAT";
1201 case DDERR_INVALIDRECT:
1202 return "DDERR_INVALIDRECT";
1203 case DDERR_LOCKEDSURFACES:
1204 return "DDERR_LOCKEDSURFACES";
1206 return "DDERR_NO3D";
1207 case DDERR_NOALPHAHW:
1208 return "DDERR_NOALPHAHW";
1209 case DDERR_NOCLIPLIST:
1210 return "DDERR_NOCLIPLIST";
1211 case DDERR_NOCOLORCONVHW:
1212 return "DDERR_NOCOLORCONVHW";
1213 case DDERR_NOCOOPERATIVELEVELSET:
1214 return "DDERR_NOCOOPERATIVELEVELSET";
1215 case DDERR_NOCOLORKEY:
1216 return "DDERR_NOCOLORKEY";
1217 case DDERR_NOCOLORKEYHW:
1218 return "DDERR_NOCOLORKEYHW";
1219 case DDERR_NODIRECTDRAWSUPPORT:
1220 return "DDERR_NODIRECTDRAWSUPPORT";
1221 case DDERR_NOEXCLUSIVEMODE:
1222 return "DDERR_NOEXCLUSIVEMODE";
1223 case DDERR_NOFLIPHW:
1224 return "DDERR_NOFLIPHW";
1226 return "DDERR_NOGDI";
1227 case DDERR_NOMIRRORHW:
1228 return "DDERR_NOMIRRORHW";
1229 case DDERR_NOTFOUND:
1230 return "DDERR_NOTFOUND";
1231 case DDERR_NOOVERLAYHW:
1232 return "DDERR_NOOVERLAYHW";
1233 case DDERR_NORASTEROPHW:
1234 return "DDERR_NORASTEROPHW";
1235 case DDERR_NOROTATIONHW:
1236 return "DDERR_NOROTATIONHW";
1237 case DDERR_NOSTRETCHHW:
1238 return "DDERR_NOSTRETCHHW";
1239 case DDERR_NOT4BITCOLOR:
1240 return "DDERR_NOT4BITCOLOR";
1241 case DDERR_NOT4BITCOLORINDEX:
1242 return "DDERR_NOT4BITCOLORINDEX";
1243 case DDERR_NOT8BITCOLOR:
1244 return "DDERR_NOT8BITCOLOR";
1245 case DDERR_NOTEXTUREHW:
1246 return "DDERR_NOTEXTUREHW";
1247 case DDERR_NOVSYNCHW:
1248 return "DDERR_NOVSYNCHW";
1249 case DDERR_NOZBUFFERHW:
1250 return "DDERR_NOZBUFFERHW";
1251 case DDERR_NOZOVERLAYHW:
1252 return "DDERR_NOZOVERLAYHW";
1253 case DDERR_OUTOFCAPS:
1254 return "DDERR_OUTOFCAPS";
1255 case DDERR_OUTOFMEMORY:
1256 return "DDERR_OUTOFMEMORY";
1257 case DDERR_OUTOFVIDEOMEMORY:
1258 return "DDERR_OUTOFVIDEOMEMORY";
1259 case DDERR_OVERLAYCANTCLIP:
1260 return "DDERR_OVERLAYCANTCLIP";
1261 case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
1262 return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
1263 case DDERR_PALETTEBUSY:
1264 return "DDERR_PALETTEBUSY";
1265 case DDERR_COLORKEYNOTSET:
1266 return "DDERR_COLORKEYNOTSET";
1267 case DDERR_SURFACEALREADYATTACHED:
1268 return "DDERR_SURFACEALREADYATTACHED";
1269 case DDERR_SURFACEALREADYDEPENDENT:
1270 return "DDERR_SURFACEALREADYDEPENDENT";
1271 case DDERR_SURFACEBUSY:
1272 return "DDERR_SURFACEBUSY";
1273 case DDERR_CANTLOCKSURFACE:
1274 return "DDERR_CANTLOCKSURFACE";
1275 case DDERR_SURFACEISOBSCURED:
1276 return "DDERR_SURFACEISOBSCURED";
1277 case DDERR_SURFACELOST:
1278 return "DDERR_SURFACELOST";
1279 case DDERR_SURFACENOTATTACHED:
1280 return "DDERR_SURFACENOTATTACHED";
1281 case DDERR_TOOBIGHEIGHT:
1282 return "DDERR_TOOBIGHEIGHT";
1283 case DDERR_TOOBIGSIZE:
1284 return "DDERR_TOOBIGSIZE";
1285 case DDERR_TOOBIGWIDTH:
1286 return "DDERR_TOOBIGWIDTH";
1287 case DDERR_UNSUPPORTED:
1288 return "DDERR_UNSUPPORTED";
1289 case DDERR_UNSUPPORTEDFORMAT:
1290 return "DDERR_UNSUPPORTEDFORMAT";
1291 case DDERR_UNSUPPORTEDMASK:
1292 return "DDERR_UNSUPPORTEDMASK";
1293 case DDERR_VERTICALBLANKINPROGRESS:
1294 return "DDERR_VERTICALBLANKINPROGRESS";
1295 case DDERR_WASSTILLDRAWING:
1296 return "DDERR_WASSTILLDRAWING";
1298 return "DDERR_XALIGN";
1299 case DDERR_INVALIDDIRECTDRAWGUID:
1300 return "DDERR_INVALIDDIRECTDRAWGUID";
1301 case DDERR_DIRECTDRAWALREADYCREATED:
1302 return "DDERR_DIRECTDRAWALREADYCREATED";
1303 case DDERR_NODIRECTDRAWHW:
1304 return "DDERR_NODIRECTDRAWHW";
1305 case DDERR_PRIMARYSURFACEALREADYEXISTS:
1306 return "DDERR_PRIMARYSURFACEALREADYEXISTS";
1307 case DDERR_NOEMULATION:
1308 return "DDERR_NOEMULATION";
1309 case DDERR_REGIONTOOSMALL:
1310 return "DDERR_REGIONTOOSMALL";
1311 case DDERR_CLIPPERISUSINGHWND:
1312 return "DDERR_CLIPPERISUSINGHWND";
1313 case DDERR_NOCLIPPERATTACHED:
1314 return "DDERR_NOCLIPPERATTACHED";
1316 return "DDERR_NOHWND";
1317 case DDERR_HWNDSUBCLASSED:
1318 return "DDERR_HWNDSUBCLASSED";
1319 case DDERR_HWNDALREADYSET:
1320 return "DDERR_HWNDALREADYSET";
1321 case DDERR_NOPALETTEATTACHED:
1322 return "DDERR_NOPALETTEATTACHED";
1323 case DDERR_NOPALETTEHW:
1324 return "DDERR_NOPALETTEHW";
1325 case DDERR_BLTFASTCANTCLIP:
1326 return "DDERR_BLTFASTCANTCLIP";
1328 return "DDERR_NOBLTHW";
1329 case DDERR_NODDROPSHW:
1330 return "DDERR_NODDROPSHW";
1331 case DDERR_OVERLAYNOTVISIBLE:
1332 return "DDERR_OVERLAYNOTVISIBLE";
1333 case DDERR_NOOVERLAYDEST:
1334 return "DDERR_NOOVERLAYDEST";
1335 case DDERR_INVALIDPOSITION:
1336 return "DDERR_INVALIDPOSITION";
1337 case DDERR_NOTAOVERLAYSURFACE:
1338 return "DDERR_NOTAOVERLAYSURFACE";
1339 case DDERR_EXCLUSIVEMODEALREADYSET:
1340 return "DDERR_EXCLUSIVEMODEALREADYSET";
1341 case DDERR_NOTFLIPPABLE:
1342 return "DDERR_NOTFLIPPABLE";
1343 case DDERR_CANTDUPLICATE:
1344 return "DDERR_CANTDUPLICATE";
1345 case DDERR_NOTLOCKED:
1346 return "DDERR_NOTLOCKED";
1347 case DDERR_CANTCREATEDC:
1348 return "DDERR_CANTCREATEDC";
1350 return "DDERR_NODC";
1351 case DDERR_WRONGMODE:
1352 return "DDERR_WRONGMODE";
1353 case DDERR_IMPLICITLYCREATED:
1354 return "DDERR_IMPLICITLYCREATED";
1355 case DDERR_NOTPALETTIZED:
1356 return "DDERR_NOTPALETTIZED";
1357 case DDERR_UNSUPPORTEDMODE:
1358 return "DDERR_UNSUPPORTEDMODE";
1359 case DDERR_NOMIPMAPHW:
1360 return "DDERR_NOMIPMAPHW";
1361 case DDERR_INVALIDSURFACETYPE:
1362 return "DDERR_INVALIDSURFACETYPE";
1363 case DDERR_DCALREADYCREATED:
1364 return "DDERR_DCALREADYCREATED";
1365 case DDERR_CANTPAGELOCK:
1366 return "DDERR_CANTPAGELOCK";
1367 case DDERR_CANTPAGEUNLOCK:
1368 return "DDERR_CANTPAGEUNLOCK";
1369 case DDERR_NOTPAGELOCKED:
1370 return "DDERR_NOTPAGELOCKED";
1371 case DDERR_NOTINITIALIZED:
1372 return "DDERR_NOTINITIALIZED";
1374 return "Unknown Error";
1378 gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1380 gboolean bRet = TRUE;
1382 /* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first
1383 * parameter to force Directdraw to use the hardware emulation layer */
1384 hRes = DirectDrawCreateEx ( /*DDCREATE_EMULATIONONLY */ 0,
1385 (void **) &ddrawsink->ddraw_object, &IID_IDirectDraw7, NULL);
1386 if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
1387 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1388 ("Failed to create the DirectDraw object error=%s",
1389 DDErrorString (hRes)), (NULL));
1393 /* set cooperative level */
1394 hRes = IDirectDraw7_SetCooperativeLevel (ddrawsink->ddraw_object,
1395 NULL, DDSCL_NORMAL);
1396 if (hRes != DD_OK) {
1397 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1398 ("Failed to set the set the cooperative level error=%s",
1399 DDErrorString (hRes)), (NULL));
1403 /* setup the clipper object */
1404 hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
1405 &ddrawsink->clipper, NULL);
1407 if (hRes == DD_OK && ddrawsink->video_window)
1408 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1410 /* create our primary surface */
1411 if (!gst_directdraw_sink_check_primary_surface (ddrawsink))
1414 /* directdraw objects are setup */
1415 ddrawsink->setup = TRUE;
1420 static LRESULT FAR PASCAL
1421 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1425 LPCREATESTRUCT crs = (LPCREATESTRUCT) lParam;
1426 /* Nail pointer to the video sink down to this window */
1427 SetWindowLongPtr (hWnd, GWLP_USERDATA, (LONG_PTR) crs->lpCreateParams);
1434 case WM_LBUTTONDOWN:
1435 case WM_RBUTTONDOWN:
1436 case WM_MBUTTONDOWN:
1441 GstDirectDrawSink *ddrawsink;
1442 ddrawsink = (GstDirectDrawSink *) GetWindowLongPtr (hWnd, GWLP_USERDATA);
1444 if (G_UNLIKELY (!ddrawsink))
1449 GST_OBJECT_LOCK (ddrawsink);
1450 ddrawsink->out_width = LOWORD (lParam);
1451 ddrawsink->out_height = HIWORD (lParam);
1452 GST_OBJECT_UNLOCK (ddrawsink);
1453 GST_DEBUG_OBJECT (ddrawsink, "Window size is %dx%d", LOWORD (wParam),
1460 gunichar2 wcrep[128];
1461 if (GetKeyNameTextW (lParam, wcrep, 128)) {
1462 gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
1464 if (message == WM_CHAR || message == WM_KEYDOWN)
1465 gst_navigation_send_key_event (GST_NAVIGATION (ddrawsink),
1466 "key-press", utfrep);
1467 if (message == WM_CHAR || message == WM_KEYUP)
1468 gst_navigation_send_key_event (GST_NAVIGATION (ddrawsink),
1469 "key-release", utfrep);
1475 case WM_LBUTTONDOWN:
1477 case WM_RBUTTONDOWN:
1479 case WM_MBUTTONDOWN:
1483 const gchar *action;
1488 action = "mouse-move";
1490 case WM_LBUTTONDOWN:
1492 action = "mouse-button-press";
1496 action = "mouse-button-release";
1498 case WM_RBUTTONDOWN:
1500 action = "mouse-button-press";
1504 action = "mouse-button-release";
1506 case WM_MBUTTONDOWN:
1508 action = "mouse-button-press";
1512 action = "mouse-button-release";
1519 x = LOWORD (lParam);
1520 y = HIWORD (lParam);
1523 GST_DEBUG_OBJECT (ddrawsink, "Mouse moved to %dx%d", x, y);
1525 GST_DEBUG_OBJECT (ddrawsink, "Mouse button %d pressed at %dx%d",
1529 gst_navigation_send_mouse_event (GST_NAVIGATION (ddrawsink),
1530 action, button, x, y);
1540 DestroyWindow (hWnd);
1542 PostQuitMessage (0);
1546 return DefWindowProc (hWnd, message, wParam, lParam);
1550 gst_directdraw_sink_window_thread (GstDirectDrawSink * ddrawsink)
1555 memset (&WndClass, 0, sizeof (WNDCLASS));
1556 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1557 WndClass.hInstance = GetModuleHandle (NULL);
1558 WndClass.lpszClassName = "GStreamer-DirectDraw";
1559 WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
1560 WndClass.cbClsExtra = 0;
1561 WndClass.cbWndExtra = 0;
1562 WndClass.lpfnWndProc = WndProc;
1563 WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
1564 RegisterClass (&WndClass);
1566 ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
1567 "GStreamer-DirectDraw sink default window",
1568 WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
1569 WndClass.hInstance, (LPVOID) ddrawsink);
1570 if (ddrawsink->video_window == NULL)
1573 /* Set the clipper on that window */
1574 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1576 /* signal application we created a window */
1577 gst_x_overlay_got_window_handle (GST_X_OVERLAY (ddrawsink),
1578 (guintptr) ddrawsink->video_window);
1580 ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1582 /* start message loop processing our default window messages */
1583 while (GetMessage (&msg, NULL, 0, 0) != FALSE) {
1584 TranslateMessage (&msg);
1585 DispatchMessage (&msg);
1588 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1589 "our window received WM_QUIT or error.");
1590 /* The window could have changed, if it is not ours anymore we don't
1591 * overwrite the current video window with NULL */
1592 if (ddrawsink->our_video_window) {
1593 GST_OBJECT_LOCK (ddrawsink);
1594 ddrawsink->video_window = NULL;
1595 GST_OBJECT_UNLOCK (ddrawsink);
1602 gst_directdraw_sink_create_default_window (GstDirectDrawSink * ddrawsink)
1604 ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1605 if (ddrawsink->window_created_signal == NULL)
1608 ddrawsink->window_thread = g_thread_create (
1609 (GThreadFunc) gst_directdraw_sink_window_thread, ddrawsink, TRUE, NULL);
1611 if (ddrawsink->window_thread == NULL)
1614 /* wait maximum 10 seconds for windows creating */
1615 if (WaitForSingleObject (ddrawsink->window_created_signal,
1616 10000) != WAIT_OBJECT_0)
1619 CloseHandle (ddrawsink->window_created_signal);
1623 CloseHandle (ddrawsink->window_created_signal);
1624 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1625 ("Error creating our default window"), (NULL));
1631 gst_directdraw_sink_check_primary_surface (GstDirectDrawSink * ddrawsink)
1634 DDSURFACEDESC2 dd_surface_desc;
1637 /* if our primary surface already exist, check if it's not lost */
1638 if (ddrawsink->primary_surface) {
1639 if (IDirectDrawSurface7_IsLost (ddrawsink->primary_surface) == DD_OK) {
1640 /* no problem with our primary surface */
1643 /* our primary surface was lost, try to restore it */
1644 if (IDirectDrawSurface7_Restore (ddrawsink->primary_surface) == DD_OK) {
1645 /* restore is done */
1646 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1647 "Our primary surface" " was restored after lost");
1650 /* failed to restore our primary surface,
1651 * probably because the display mode was changed.
1652 * Release this surface and recreate a new one.
1654 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1655 "Our primary surface"
1656 " was lost and display mode has changed. Destroy and recreate our surface.");
1657 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
1658 ddrawsink->primary_surface = NULL;
1660 /* also release offscreen surface */
1661 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1662 ddrawsink->offscreen_surface = NULL;
1667 /* create our primary surface */
1668 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1669 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1670 dd_surface_desc.dwFlags = DDSD_CAPS;
1671 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1672 sd = &dd_surface_desc;
1674 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1675 &ddrawsink->primary_surface, NULL);
1676 if (hres != DD_OK) {
1677 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1678 ("Failed to create our primary surface error=%s", DDErrorString (hres)),
1683 /* attach our clipper object to the new primary surface */
1684 if (ddrawsink->clipper) {
1685 hres = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
1686 ddrawsink->clipper);
1693 gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink * ddrawsink)
1695 DDSURFACEDESC2 dd_surface_desc;
1699 /* if our offscreen surface already exist, check if it's not lost */
1700 if (ddrawsink->offscreen_surface) {
1701 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK) {
1702 /* no problem with our offscreen surface */
1705 /* our offscreen surface was lost, try to restore it */
1706 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
1707 /* restore is done */
1708 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1709 "Our offscreen surface" " was restored after lost");
1712 /* failed to restore our offscreen surface,
1713 * probably because the display mode was changed.
1714 * Release this surface and recreate a new one.
1716 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1717 "Our offscreen surface"
1718 " was lost and display mode has changed. Destroy and recreate our surface.");
1719 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1720 ddrawsink->offscreen_surface = NULL;
1725 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1726 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1727 dd_surface_desc.dwFlags =
1728 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1729 dd_surface_desc.dwHeight = ddrawsink->video_height;
1730 dd_surface_desc.dwWidth = ddrawsink->video_width;
1731 memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
1732 sizeof (DDPIXELFORMAT));
1734 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1735 sd = &dd_surface_desc;
1737 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1738 &ddrawsink->offscreen_surface, NULL);
1739 if (hres != DD_OK) {
1740 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1741 "create_ddraw_surface:CreateSurface (offscreen surface for buffer_pool) failed %s",
1742 DDErrorString (hres));
1746 ddrawsink->must_recreate_offscreen = FALSE;
1752 gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1754 gint order = 0, binary;
1758 dwRBitMask | lpddpfPixelFormat->dwGBitMask | lpddpfPixelFormat->
1759 dwBBitMask | lpddpfPixelFormat->dwRGBAlphaBitMask;
1760 while (binary != 0) {
1761 if ((binary % 2) == 1)
1763 binary = binary >> 1;
1768 static HRESULT WINAPI
1769 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1771 GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1772 GstCaps *format_caps = NULL;
1773 LPDDSURFACEDESC2 sd;
1775 if (!ddrawsink || !lpDDSurfaceDesc)
1776 return DDENUMRET_CANCEL;
1778 sd = (LPDDSURFACEDESC2) lpDDSurfaceDesc;
1779 if ((sd->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
1780 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1781 "Display mode found with DDSD_PIXELFORMAT not set");
1782 return DDENUMRET_OK;
1785 if ((sd->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1786 return DDENUMRET_OK;
1788 format_caps = gst_directdraw_sink_create_caps_from_surfacedesc (sd);
1791 gst_caps_append (ddrawsink->caps, format_caps);
1794 return DDENUMRET_OK;
1798 gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc)
1800 GstCaps *caps = NULL;
1801 gint endianness = G_LITTLE_ENDIAN;
1804 if ((desc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1807 depth = gst_directdraw_sink_get_depth (&desc->ddpfPixelFormat);
1809 if (desc->ddpfPixelFormat.dwRGBBitCount == 24 ||
1810 desc->ddpfPixelFormat.dwRGBBitCount == 32) {
1811 /* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
1812 endianness = G_BIG_ENDIAN;
1813 desc->ddpfPixelFormat.dwRBitMask =
1814 GUINT32_TO_BE (desc->ddpfPixelFormat.dwRBitMask);
1815 desc->ddpfPixelFormat.dwGBitMask =
1816 GUINT32_TO_BE (desc->ddpfPixelFormat.dwGBitMask);
1817 desc->ddpfPixelFormat.dwBBitMask =
1818 GUINT32_TO_BE (desc->ddpfPixelFormat.dwBBitMask);
1819 if (desc->ddpfPixelFormat.dwRGBBitCount == 24) {
1820 desc->ddpfPixelFormat.dwRBitMask >>= 8;
1821 desc->ddpfPixelFormat.dwGBitMask >>= 8;
1822 desc->ddpfPixelFormat.dwBBitMask >>= 8;
1826 caps = gst_caps_new_simple ("video/x-raw-rgb",
1827 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1828 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1829 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
1830 "bpp", G_TYPE_INT, desc->ddpfPixelFormat.dwRGBBitCount,
1831 "depth", G_TYPE_INT, depth,
1832 "endianness", G_TYPE_INT, endianness,
1833 "red_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwRBitMask,
1834 "green_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwGBitMask,
1835 "blue_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwBBitMask, NULL);
1841 gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1843 HRESULT hRes = S_OK;
1844 DDCAPS ddcaps_hardware;
1845 DDCAPS ddcaps_emulation;
1846 GstCaps *format_caps = NULL;
1848 ddrawsink->caps = gst_caps_new_empty ();
1849 if (!ddrawsink->caps)
1852 /* get hardware caps */
1853 ddcaps_hardware.dwSize = sizeof (DDCAPS);
1854 ddcaps_emulation.dwSize = sizeof (DDCAPS);
1855 IDirectDraw7_GetCaps (ddrawsink->ddraw_object, &ddcaps_hardware,
1858 /* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw
1859 * emulation layer can do it */
1860 if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
1861 DDSURFACEDESC2 surface_desc;
1864 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1865 "hardware doesn't support blit from one colorspace to another one. "
1866 "so we will create a caps with only the current display mode");
1868 /* save blit caps */
1869 ddrawsink->can_blit_between_colorspace = FALSE;
1871 surface_desc.dwSize = sizeof (surface_desc);
1874 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
1875 (DDSURFACEDESC *) sd);
1876 if (hRes != DD_OK) {
1877 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1878 ("Error getting the current display mode error=%s",
1879 DDErrorString (hRes)), (NULL));
1884 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
1886 gst_caps_append (ddrawsink->caps, format_caps);
1889 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1890 gst_caps_to_string (ddrawsink->caps));
1891 return ddrawsink->caps;
1894 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1895 "the hardware can blit from one colorspace to another, "
1896 "then enumerate the colorspace supported by the hardware");
1898 /* save blit caps */
1899 ddrawsink->can_blit_between_colorspace = TRUE;
1901 /* enumerate display modes exposed by directdraw object
1902 to know supported RGB modes */
1904 IDirectDraw7_EnumDisplayModes (ddrawsink->ddraw_object,
1905 DDEDM_REFRESHRATES, NULL, ddrawsink, EnumModesCallback2);
1906 if (hRes != DD_OK) {
1907 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1908 ("Error enumerating display modes error=%s", DDErrorString (hRes)),
1914 if (gst_caps_is_empty (ddrawsink->caps)) {
1915 gst_caps_unref (ddrawsink->caps);
1916 ddrawsink->caps = NULL;
1917 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1918 ("No supported caps found."), (NULL));
1922 /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1923 * gst_caps_to_string (ddrawsink->caps)); */
1925 return ddrawsink->caps;
1928 /* Creates miniobject and our internal surface */
1929 static GstDDrawSurface *
1930 gst_directdraw_sink_surface_create (GstDirectDrawSink * ddrawsink,
1931 GstCaps * caps, size_t size)
1933 GstDDrawSurface *surface = NULL;
1934 GstStructure *structure = NULL;
1940 DDSURFACEDESC2 surf_desc, surf_lock_desc;
1942 g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1944 /*init structures */
1945 memset (&surf_desc, 0, sizeof (surf_desc));
1946 memset (&surf_lock_desc, 0, sizeof (surf_desc));
1947 surf_desc.dwSize = sizeof (surf_desc);
1948 surf_lock_desc.dwSize = sizeof (surf_lock_desc);
1950 /*create miniobject and initialize it */
1951 surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1952 surface->locked = FALSE;
1954 structure = gst_caps_get_structure (caps, 0);
1955 if (!gst_structure_get_int (structure, "width", &surface->width) ||
1956 !gst_structure_get_int (structure, "height", &surface->height)) {
1957 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1958 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
1961 pitch = GST_ROUND_UP_8 (size / surface->height);
1962 if (!gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
1963 &surface->dd_pixel_format)) {
1964 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1965 "failed getting pixel format from caps %" GST_PTR_FORMAT, caps);
1968 /* disable return of directdraw surface to buffer alloc because actually I
1969 * have no solution to handle display mode changes. The problem is that when
1970 * the display mode is changed surface's memory is freed then the upstream
1971 * filter would crash trying to write to this memory. Directdraw has a system
1972 * lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
1973 * when a surface memory is locked but we need to disable this lock to return
1974 * multiple buffers (surfaces) and do not lock directdraw API calls.
1977 /* if (ddrawsink->ddraw_object) {*/
1978 /* Creating an internal surface which will be used as GstBuffer, we used
1979 the detected pixel format and video dimensions */
1981 surf_desc.ddsCaps.dwCaps =
1982 DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1984 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1985 surf_desc.dwHeight = surface->height;
1986 surf_desc.dwWidth = surface->width;
1987 memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1988 sizeof (DDPIXELFORMAT));
1990 hRes = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1991 &surface->surface, NULL);
1992 if (hRes != DD_OK) {
1993 goto surface_pitch_bad;
1996 /* Locking the surface to acquire the memory pointer.
1997 Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
1998 if directdraw api is used while a buffer is lock */
2000 hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
2001 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
2002 if (hRes == DDERR_SURFACELOST) {
2003 IDirectDrawSurface7_Restore (surface->surface);
2006 surface->locked = TRUE;
2008 if (surf_lock_desc.lPitch != pitch) {
2009 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
2010 "DDraw stride/pitch %ld isn't as expected value %d, let's continue allocating a system memory buffer.",
2011 surf_lock_desc.lPitch, pitch);
2013 /*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
2014 hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
2015 goto surface_pitch_bad;
2017 GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
2018 GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
2019 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
2020 "allocating a surface of %d bytes (stride=%ld)\n", size,
2021 surf_lock_desc.lPitch);
2025 GST_BUFFER (surface)->malloc_data = g_malloc (size);
2026 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
2027 GST_BUFFER_SIZE (surface) = size;
2028 surface->surface = NULL;
2029 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
2030 "allocating a system memory buffer of %" G_GSIZE_FORMAT " bytes", size);
2034 /* Keep a ref to our sink */
2035 surface->ddrawsink = gst_object_ref (ddrawsink);
2040 /* We are called from the finalize method of miniobject, the object will be
2041 * destroyed so we just have to clean our internal stuff */
2043 gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
2044 GstDDrawSurface * surface)
2046 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
2048 /* Release our internal surface */
2049 if (surface->surface) {
2050 if (surface->locked) {
2051 IDirectDrawSurface7_Unlock (surface->surface, NULL);
2052 surface->locked = FALSE;
2054 IDirectDrawSurface7_Release (surface->surface);
2055 surface->surface = NULL;
2058 if (GST_BUFFER (surface)->malloc_data) {
2059 g_free (GST_BUFFER (surface)->malloc_data);
2060 GST_BUFFER (surface)->malloc_data = NULL;
2063 if (!surface->ddrawsink) {
2067 /* Release the ref to our sink */
2068 surface->ddrawsink = NULL;
2069 gst_object_unref (ddrawsink);
2074 GST_WARNING ("no sink found in surface");
2079 gst_directdraw_sink_surface_check (GstDirectDrawSink * ddrawsink,
2080 GstDDrawSurface * surface)
2082 if (!surface->surface)
2083 return TRUE; /* system memory buffer */
2085 if (IDirectDrawSurface7_IsLost (surface->surface) == DD_OK) {
2086 /* no problem with this surface */
2089 /* this surface was lost, try to restore it */
2090 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
2091 /* restore is done */
2092 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink, "A surface from our"
2093 " bufferpool was restored after lost");
2102 gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
2104 g_mutex_lock (ddrawsink->pool_lock);
2105 while (ddrawsink->buffer_pool) {
2106 GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
2108 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
2109 ddrawsink->buffer_pool);
2110 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
2111 gst_buffer_unref (GST_BUFFER_CAST (surface));
2113 g_mutex_unlock (ddrawsink->pool_lock);
2117 gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink)
2119 /* Post quit message and wait for our event window thread */
2120 if (ddrawsink->video_window && ddrawsink->our_video_window)
2121 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
2123 if (ddrawsink->window_thread) {
2124 g_thread_join (ddrawsink->window_thread);
2125 ddrawsink->window_thread = NULL;
2128 if (ddrawsink->buffer_pool) {
2129 gst_directdraw_sink_bufferpool_clear (ddrawsink);
2130 ddrawsink->buffer_pool = NULL;
2133 if (ddrawsink->offscreen_surface) {
2134 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
2135 ddrawsink->offscreen_surface = NULL;
2138 if (ddrawsink->clipper) {
2139 IDirectDrawClipper_Release (ddrawsink->clipper);
2140 ddrawsink->clipper = NULL;
2143 if (ddrawsink->primary_surface) {
2144 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
2145 ddrawsink->primary_surface = NULL;
2148 if (ddrawsink->ddraw_object) {
2149 IDirectDraw7_Release (ddrawsink->ddraw_object);
2150 ddrawsink->ddraw_object = NULL;
2153 if (ddrawsink->last_buffer) {
2154 gst_buffer_unref (ddrawsink->last_buffer);
2155 ddrawsink->last_buffer = NULL;
2158 ddrawsink->setup = FALSE;