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 -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 static void gst_directdraw_sink_init_interfaces (GType type);
53 GST_BOILERPLATE_FULL (GstDirectDrawSink, gst_directdraw_sink, GstVideoSink,
54 GST_TYPE_VIDEO_SINK, gst_directdraw_sink_init_interfaces);
56 static void gst_directdraw_sink_finalize (GObject * object);
57 static void gst_directdraw_sink_set_property (GObject * object,
58 guint prop_id, const GValue * value, GParamSpec * pspec);
59 static void gst_directdraw_sink_get_property (GObject * object,
60 guint prop_id, GValue * value, GParamSpec * pspec);
61 static GstCaps *gst_directdraw_sink_get_caps (GstBaseSink * bsink);
62 static gboolean gst_directdraw_sink_set_caps (GstBaseSink * bsink,
64 static GstStateChangeReturn gst_directdraw_sink_change_state (GstElement *
65 element, GstStateChange transition);
66 static GstFlowReturn gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink,
67 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
68 static void gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
69 GstClockTime * start, GstClockTime * end);
70 static GstFlowReturn gst_directdraw_sink_show_frame (GstBaseSink * bsink,
74 static gboolean gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink);
75 static gboolean gst_directdraw_sink_create_default_window (GstDirectDrawSink *
77 static gboolean gst_directdraw_sink_check_primary_surface (GstDirectDrawSink *
79 static gboolean gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink *
81 static GstCaps *gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink *
84 * gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc);
85 static void gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink);
86 static void gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink *
88 static int gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat);
89 static gboolean gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink *
90 ddrawsink, GstCaps * caps, DDPIXELFORMAT * pPixelFormat);
91 static void gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink,
92 RECT src, RECT dst, RECT * result);
93 static const char *DDErrorString (HRESULT hr);
95 /* surfaces management functions */
96 static void gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
97 GstDDrawSurface * surface);
98 static GstDDrawSurface *gst_directdraw_sink_surface_create (GstDirectDrawSink *
99 ddrawsink, GstCaps * caps, size_t size);
100 static gboolean gst_directdraw_sink_surface_check (GstDirectDrawSink *
101 ddrawsink, GstDDrawSurface * surface);
103 static GstStaticPadTemplate directdrawsink_sink_factory =
104 GST_STATIC_PAD_TEMPLATE ("sink",
107 GST_STATIC_CAPS ("video/x-raw-rgb, "
108 "framerate = (fraction) [ 0, MAX ], "
109 "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
115 PROP_KEEP_ASPECT_RATIO
118 /* XOverlay interface implementation */
120 gst_directdraw_sink_interface_supported (GstImplementsInterface * iface,
123 if (type == GST_TYPE_X_OVERLAY)
125 else if (type == GST_TYPE_NAVIGATION)
131 gst_directdraw_sink_interface_init (GstImplementsInterfaceClass * klass)
133 klass->supported = gst_directdraw_sink_interface_supported;
137 gst_directdraw_sink_set_window_id (GstXOverlay * overlay, ULONG window_id)
139 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
141 GST_OBJECT_LOCK (ddrawsink);
142 /* check if we are already using this window id */
143 if (ddrawsink->video_window == (HWND) window_id) {
144 GST_OBJECT_UNLOCK (ddrawsink);
151 /* If we had an internal window, close it first */
152 if (ddrawsink->video_window && ddrawsink->our_video_window) {
153 /* Trick to let the event thread know that it has to die silently */
154 ddrawsink->our_video_window = FALSE;
155 /* Post quit message and wait for our event window thread */
156 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
159 ddrawsink->video_window = (HWND) window_id;
160 ddrawsink->our_video_window = FALSE;
161 if (ddrawsink->setup) {
162 /* update the clipper object with the new window */
163 hres = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
164 ddrawsink->video_window);
167 /* FIXME: Handle the case where window_id is 0 and we want the sink to
168 * create a new window when playback was already started (after set_caps) */
169 GST_OBJECT_UNLOCK (ddrawsink);
173 gst_directdraw_sink_expose (GstXOverlay * overlay)
175 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
177 gst_directdraw_sink_show_frame (GST_BASE_SINK (ddrawsink), NULL);
181 gst_directdraw_sink_xoverlay_interface_init (GstXOverlayClass * iface)
183 iface->set_xwindow_id = gst_directdraw_sink_set_window_id;
184 iface->expose = gst_directdraw_sink_expose;
188 gst_directdraw_sink_navigation_send_event (GstNavigation * navigation,
189 GstStructure * structure)
191 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (navigation);
193 GstVideoRectangle src, dst, result;
194 double x, y, old_x, old_y;
197 src.w = GST_VIDEO_SINK_WIDTH (ddrawsink);
198 src.h = GST_VIDEO_SINK_HEIGHT (ddrawsink);
199 dst.w = ddrawsink->out_width;
200 dst.h = ddrawsink->out_height;
201 gst_video_sink_center_rect (src, dst, &result, FALSE);
203 event = gst_event_new_navigation (structure);
205 /* Our coordinates can be wrong here if we centered the video */
207 /* Converting pointer coordinates to the non scaled geometry */
208 if (gst_structure_get_double (structure, "pointer_x", &old_x)) {
211 if (x >= result.x && x <= (result.x + result.w)) {
213 x *= ddrawsink->video_width;
218 GST_DEBUG_OBJECT (ddrawsink, "translated navigation event x "
219 "coordinate from %f to %f", old_x, x);
220 gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
222 if (gst_structure_get_double (structure, "pointer_y", &old_y)) {
225 if (y >= result.y && y <= (result.y + result.h)) {
227 y *= ddrawsink->video_height;
232 GST_DEBUG_OBJECT (ddrawsink, "translated navigation event y "
233 "coordinate from %f to %f", old_y, y);
234 gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
237 pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (ddrawsink));
239 if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
240 gst_pad_send_event (pad, event);
242 gst_object_unref (pad);
247 gst_directdraw_sink_navigation_interface_init (GstNavigationInterface * iface)
249 iface->send_event = gst_directdraw_sink_navigation_send_event;
253 gst_directdraw_sink_init_interfaces (GType type)
255 static const GInterfaceInfo iface_info = {
256 (GInterfaceInitFunc) gst_directdraw_sink_interface_init,
261 static const GInterfaceInfo xoverlay_info = {
262 (GInterfaceInitFunc) gst_directdraw_sink_xoverlay_interface_init,
267 static const GInterfaceInfo navigation_info = {
268 (GInterfaceInitFunc) gst_directdraw_sink_navigation_interface_init,
273 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
275 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
276 g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
279 /* Subclass of GstBuffer which manages buffer_pool surfaces lifetime */
280 static void gst_ddrawsurface_finalize (GstMiniObject * mini_object);
281 static GstBufferClass *ddrawsurface_parent_class = NULL;
284 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
286 surface->surface = NULL;
289 surface->ddrawsink = NULL;
290 surface->locked = FALSE;
291 surface->system_memory = FALSE;
292 memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
296 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
298 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
300 ddrawsurface_parent_class = g_type_class_peek_parent (g_class);
302 mini_object_class->finalize = GST_DEBUG_FUNCPTR (gst_ddrawsurface_finalize);
306 gst_ddrawsurface_get_type (void)
308 static GType _gst_ddrawsurface_type;
310 if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
311 static const GTypeInfo ddrawsurface_info = {
312 sizeof (GstBufferClass),
315 gst_ddrawsurface_class_init,
318 sizeof (GstDDrawSurface),
320 (GInstanceInitFunc) gst_ddrawsurface_init,
323 _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
324 "GstDDrawSurface", &ddrawsurface_info, 0);
326 return _gst_ddrawsurface_type;
330 gst_ddrawsurface_finalize (GstMiniObject * mini_object)
332 GstDirectDrawSink *ddrawsink = NULL;
333 GstDDrawSurface *surface;
335 surface = (GstDDrawSurface *) mini_object;
337 ddrawsink = surface->ddrawsink;
341 /* If our geometry changed we can't reuse that image. */
342 if ((surface->width != ddrawsink->video_width) ||
343 (surface->height != ddrawsink->video_height) ||
344 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
345 sizeof (DDPIXELFORMAT)) != 0 ||
346 !gst_directdraw_sink_surface_check (ddrawsink, surface))
348 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
349 "destroy image as its size changed %dx%d vs current %dx%d",
350 surface->width, surface->height, ddrawsink->video_width,
351 ddrawsink->video_height);
352 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
353 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
355 /* In that case we can reuse the image and add it to our image pool. */
356 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
357 "recycling image in pool");
359 /* need to increment the refcount again to recycle */
360 gst_buffer_ref (GST_BUFFER (surface));
362 g_mutex_lock (ddrawsink->pool_lock);
363 ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
364 g_mutex_unlock (ddrawsink->pool_lock);
370 GST_CAT_WARNING (directdrawsink_debug, "no sink found");
371 GST_MINI_OBJECT_CLASS (ddrawsurface_parent_class)->finalize (mini_object);
375 /************************************************************************/
376 /* Directdraw sink functions */
377 /************************************************************************/
379 gst_directdraw_sink_base_init (gpointer g_class)
381 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
383 gst_element_class_set_details_simple (element_class, "Direct Draw Video Sink",
385 "Output to a video card via Direct Draw",
386 "Sebastien Moutte <sebastien@moutte.net>");
387 gst_element_class_add_pad_template (element_class,
388 gst_static_pad_template_get (&directdrawsink_sink_factory));
392 gst_directdraw_sink_class_init (GstDirectDrawSinkClass * klass)
394 GObjectClass *gobject_class;
395 GstElementClass *gstelement_class;
396 GstBaseSinkClass *gstbasesink_class;
398 gobject_class = (GObjectClass *) klass;
399 gstbasesink_class = (GstBaseSinkClass *) klass;
400 gstelement_class = (GstElementClass *) klass;
402 GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
405 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdraw_sink_finalize);
406 gobject_class->get_property =
407 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_property);
408 gobject_class->set_property =
409 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_property);
410 gstelement_class->change_state =
411 GST_DEBUG_FUNCPTR (gst_directdraw_sink_change_state);
412 gstbasesink_class->get_caps =
413 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_caps);
414 gstbasesink_class->set_caps =
415 GST_DEBUG_FUNCPTR (gst_directdraw_sink_set_caps);
416 gstbasesink_class->preroll =
417 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
418 gstbasesink_class->render =
419 GST_DEBUG_FUNCPTR (gst_directdraw_sink_show_frame);
420 gstbasesink_class->get_times =
421 GST_DEBUG_FUNCPTR (gst_directdraw_sink_get_times);
422 gstbasesink_class->buffer_alloc =
423 GST_DEBUG_FUNCPTR (gst_directdraw_sink_buffer_alloc);
425 /* install properties */
426 /* setup aspect ratio mode */
427 g_object_class_install_property (G_OBJECT_CLASS (klass),
428 PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("force-aspect-ratio",
429 "Force aspect ratio",
430 "When enabled, scaling will respect original aspect ratio", FALSE,
435 gst_directdraw_sink_set_property (GObject * object, guint prop_id,
436 const GValue * value, GParamSpec * pspec)
438 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
441 case PROP_KEEP_ASPECT_RATIO:
442 ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
445 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
451 gst_directdraw_sink_get_property (GObject * object, guint prop_id,
452 GValue * value, GParamSpec * pspec)
454 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
457 case PROP_KEEP_ASPECT_RATIO:
458 g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
461 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
467 gst_directdraw_sink_finalize (GObject * object)
469 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (object);
471 if (ddrawsink->pool_lock) {
472 g_mutex_free (ddrawsink->pool_lock);
473 ddrawsink->pool_lock = NULL;
475 if (ddrawsink->caps) {
476 gst_caps_unref (ddrawsink->caps);
477 ddrawsink->caps = NULL;
479 if (ddrawsink->setup) {
480 gst_directdraw_sink_cleanup (ddrawsink);
483 G_OBJECT_CLASS (parent_class)->finalize (object);
487 gst_directdraw_sink_init (GstDirectDrawSink * ddrawsink,
488 GstDirectDrawSinkClass * g_class)
490 /*init members variables */
491 ddrawsink->ddraw_object = NULL;
492 ddrawsink->primary_surface = NULL;
493 ddrawsink->offscreen_surface = NULL;
494 ddrawsink->clipper = NULL;
495 ddrawsink->video_window = NULL;
496 ddrawsink->our_video_window = TRUE;
497 ddrawsink->last_buffer = NULL;
498 ddrawsink->caps = NULL;
499 ddrawsink->window_thread = NULL;
500 ddrawsink->setup = FALSE;
501 ddrawsink->buffer_pool = NULL;
502 ddrawsink->keep_aspect_ratio = FALSE;
503 ddrawsink->pool_lock = g_mutex_new ();
504 ddrawsink->can_blit_between_colorspace = TRUE;
505 ddrawsink->must_recreate_offscreen = FALSE;
506 memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
508 /*video default values */
509 ddrawsink->video_height = 0;
510 ddrawsink->video_width = 0;
511 ddrawsink->fps_n = 0;
512 ddrawsink->fps_d = 0;
516 gst_directdraw_sink_get_caps (GstBaseSink * bsink)
518 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
519 GstCaps *caps = NULL;
521 if (!ddrawsink->setup) {
522 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
524 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
525 "getcaps called and we are not setup yet, " "returning template %"
526 GST_PTR_FORMAT, caps);
528 caps = gst_caps_ref (ddrawsink->caps);
535 gst_directdraw_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
537 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
538 GstStructure *structure = NULL;
542 structure = gst_caps_get_structure (caps, 0);
546 ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
547 ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
548 fps = gst_structure_get_value (structure, "framerate");
549 ret &= (fps != NULL);
551 gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
552 &ddrawsink->dd_pixel_format);
554 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
555 ("Failed to get caps properties from caps"), (NULL));
558 GST_VIDEO_SINK_WIDTH (ddrawsink) = ddrawsink->video_width;
559 GST_VIDEO_SINK_HEIGHT (ddrawsink) = ddrawsink->video_height;
561 ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
562 ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
564 /* Notify application to set window id now */
565 if (!ddrawsink->video_window) {
566 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ddrawsink));
569 /* If we still don't have a window at that stage we create our own */
570 if (!ddrawsink->video_window) {
571 gst_directdraw_sink_create_default_window (ddrawsink);
574 /* if we are rendering to our own window, resize it to video size */
575 if (ddrawsink->video_window && ddrawsink->our_video_window) {
576 SetWindowPos (ddrawsink->video_window, NULL,
577 0, 0, ddrawsink->video_width + (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
578 ddrawsink->video_height + GetSystemMetrics (SM_CYCAPTION) +
579 (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
582 /* release the surface, we have to recreate it! */
583 if (ddrawsink->offscreen_surface) {
584 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
585 ddrawsink->offscreen_surface = NULL;
588 /* create an offscreen surface with the caps */
589 ret = gst_directdraw_sink_check_offscreen_surface (ddrawsink);
591 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
592 ("Can't create a directdraw offscreen surface with the input caps"),
599 static GstStateChangeReturn
600 gst_directdraw_sink_change_state (GstElement * element,
601 GstStateChange transition)
603 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (element);
604 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
606 switch (transition) {
607 case GST_STATE_CHANGE_NULL_TO_READY:
608 if (!gst_directdraw_sink_setup_ddraw (ddrawsink)) {
609 ret = GST_STATE_CHANGE_FAILURE;
613 if (!(ddrawsink->caps = gst_directdraw_sink_get_ddrawcaps (ddrawsink))) {
614 ret = GST_STATE_CHANGE_FAILURE;
622 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
624 switch (transition) {
625 case GST_STATE_CHANGE_PAUSED_TO_READY:
626 ddrawsink->fps_n = 0;
627 ddrawsink->fps_d = 1;
628 ddrawsink->video_width = 0;
629 ddrawsink->video_height = 0;
630 if (ddrawsink->buffer_pool)
631 gst_directdraw_sink_bufferpool_clear (ddrawsink);
633 case GST_STATE_CHANGE_READY_TO_NULL:
634 if (ddrawsink->setup)
635 gst_directdraw_sink_cleanup (ddrawsink);
646 gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
647 guint size, GstCaps * caps, GstBuffer ** buf)
649 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
650 GstStructure *structure;
652 GstDDrawSurface *surface = NULL;
653 GstFlowReturn ret = GST_FLOW_OK;
654 GstCaps *buffer_caps = caps;
655 gboolean buffercaps_unref = FALSE;
657 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
658 "a buffer of %u bytes was requested", size);
660 structure = gst_caps_get_structure (caps, 0);
661 if (!gst_structure_get_int (structure, "width", &width) ||
662 !gst_structure_get_int (structure, "height", &height)) {
663 GST_WARNING_OBJECT (ddrawsink, "invalid caps for buffer allocation %"
664 GST_PTR_FORMAT, caps);
665 return GST_FLOW_UNEXPECTED;
668 g_mutex_lock (ddrawsink->pool_lock);
670 /* Inspect our buffer pool */
671 while (ddrawsink->buffer_pool) {
672 surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
674 /* Removing from the pool */
675 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
676 ddrawsink->buffer_pool);
678 /* If the surface is invalid for our need, destroy */
679 if ((surface->width != width) ||
680 (surface->height != height) ||
681 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
682 sizeof (DDPIXELFORMAT)) ||
683 !gst_directdraw_sink_surface_check (ddrawsink, surface))
685 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
686 gst_buffer_unref (GST_BUFFER_CAST (surface));
689 /* We found a suitable surface */
695 if (!ddrawsink->can_blit_between_colorspace) {
696 /* Hardware doesn't support blit from one colorspace to another.
697 * Check if the colorspace of the current display mode has changed since
698 * the last negociation. If it's the case, we will have to renegociate
702 DDSURFACEDESC2 surface_desc;
705 if (!gst_structure_get_int (structure, "depth", (gint *) & depth)) {
706 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
707 "Can't get depth from buffer_alloc caps");
708 return GST_FLOW_ERROR;
710 surface_desc.dwSize = sizeof (surface_desc);
713 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
714 (DDSURFACEDESC *) sd);
716 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
717 "Can't get current display mode (error=%ld)", (glong) hres);
718 return GST_FLOW_ERROR;
721 if (depth != gst_directdraw_sink_get_depth (&surface_desc.ddpfPixelFormat)) {
722 GstCaps *copy_caps = NULL;
723 GstStructure *copy_structure = NULL;
724 GstCaps *display_caps = NULL;
725 GstStructure *display_structure = NULL;
727 /* make a copy of the original caps */
728 copy_caps = gst_caps_copy (caps);
729 copy_structure = gst_caps_get_structure (copy_caps, 0);
732 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
734 display_structure = gst_caps_get_structure (display_caps, 0);
735 if (display_structure) {
736 gint bpp, endianness, red_mask, green_mask, blue_mask;
738 /* get new display mode properties */
739 gst_structure_get_int (display_structure, "depth", (gint *) & depth);
740 gst_structure_get_int (display_structure, "bpp", &bpp);
741 gst_structure_get_int (display_structure, "endianness", &endianness);
742 gst_structure_get_int (display_structure, "red_mask", &red_mask);
743 gst_structure_get_int (display_structure, "green_mask", &green_mask);
744 gst_structure_get_int (display_structure, "blue_mask", &blue_mask);
746 /* apply the new display mode changes to the previous caps */
747 gst_structure_set (copy_structure,
748 "bpp", G_TYPE_INT, bpp,
749 "depth", G_TYPE_INT, depth,
750 "endianness", G_TYPE_INT, endianness,
751 "red_mask", G_TYPE_INT, red_mask,
752 "green_mask", G_TYPE_INT, green_mask,
753 "blue_mask", G_TYPE_INT, blue_mask, NULL);
755 if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ddrawsink),
757 buffer_caps = copy_caps;
758 buffercaps_unref = TRUE;
759 /* update buffer size needed to store video frames according to new caps */
760 size = width * height * (bpp / 8);
762 /* update our member pixel format */
763 gst_ddrawvideosink_get_format_from_caps (ddrawsink, buffer_caps,
764 &ddrawsink->dd_pixel_format);
765 ddrawsink->must_recreate_offscreen = TRUE;
767 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
768 " desired caps %s \n\n new caps %s", gst_caps_to_string (caps),
769 gst_caps_to_string (buffer_caps));
771 GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
772 "peer refused caps re-negociation "
773 "and we can't render with the current caps.");
774 ret = GST_FLOW_ERROR;
777 gst_caps_unref (display_caps);
780 if (!buffercaps_unref)
781 gst_caps_unref (copy_caps);
785 /* We haven't found anything, creating a new one */
787 surface = gst_directdraw_sink_surface_create (ddrawsink, buffer_caps, size);
790 /* Now we should have a surface, set appropriate caps on it */
792 GST_BUFFER_FLAGS (GST_BUFFER (surface)) = 0;
793 gst_buffer_set_caps (GST_BUFFER (surface), buffer_caps);
796 g_mutex_unlock (ddrawsink->pool_lock);
798 *buf = GST_BUFFER (surface);
800 if (buffercaps_unref)
801 gst_caps_unref (buffer_caps);
807 gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect)
809 RECT win_rect, fill_rect;
813 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
815 /* Get the target window rect */
818 ClientToScreen (ddrawsink->video_window, &win_point);
819 GetClientRect (ddrawsink->video_window, &win_rect);
820 OffsetRect (&win_rect, win_point.x, win_point.y);
822 /* We acquire a drawing context */
823 if (IDirectDrawSurface7_GetDC (ddrawsink->primary_surface, &hdc) == DD_OK) {
824 HBRUSH brush = CreateSolidBrush (RGB (0, 0, 0));
827 if (dst_rect.left > win_rect.left) {
828 fill_rect.left = win_rect.left;
829 fill_rect.top = win_rect.top;
830 fill_rect.bottom = win_rect.bottom;
831 fill_rect.right = dst_rect.left;
832 FillRect (hdc, &fill_rect, brush);
835 if (dst_rect.right < win_rect.right) {
836 fill_rect.top = win_rect.top;
837 fill_rect.left = dst_rect.right;
838 fill_rect.bottom = win_rect.bottom;
839 fill_rect.right = win_rect.right;
840 FillRect (hdc, &fill_rect, brush);
843 if (dst_rect.top > win_rect.top) {
844 fill_rect.top = win_rect.top;
845 fill_rect.left = win_rect.left;
846 fill_rect.right = win_rect.right;
847 fill_rect.bottom = dst_rect.top;
848 FillRect (hdc, &fill_rect, brush);
851 if (dst_rect.bottom < win_rect.bottom) {
852 fill_rect.top = dst_rect.bottom;
853 fill_rect.left = win_rect.left;
854 fill_rect.right = win_rect.right;
855 fill_rect.bottom = win_rect.bottom;
856 FillRect (hdc, &fill_rect, brush);
858 DeleteObject (brush);
859 IDirectDrawSurface7_ReleaseDC (ddrawsink->primary_surface, hdc);
864 gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
866 GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
868 RECT destsurf_rect, src_rect;
869 POINT dest_surf_point;
872 /* save a reference to the input buffer */
873 gst_buffer_ref (buf);
874 if (ddrawsink->last_buffer != NULL)
875 gst_buffer_unref (ddrawsink->last_buffer);
876 ddrawsink->last_buffer = buf;
878 /* use last buffer */
879 buf = ddrawsink->last_buffer;
883 GST_ERROR_OBJECT (ddrawsink, "No buffer to render.");
884 return GST_FLOW_ERROR;
885 } else if (!ddrawsink->video_window) {
886 GST_WARNING_OBJECT (ddrawsink, "No video window to render to.");
887 return GST_FLOW_ERROR;
890 /* get the video window position */
891 GST_OBJECT_LOCK (ddrawsink);
892 if (G_UNLIKELY (!ddrawsink->video_window)) {
893 GST_OBJECT_UNLOCK (ddrawsink);
894 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
895 "gst_directdraw_sink_show_frame our video window disappeared");
896 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, NOT_FOUND,
897 ("Output window was closed"), (NULL));
898 return GST_FLOW_ERROR;
900 dest_surf_point.x = 0;
901 dest_surf_point.y = 0;
902 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
903 GetClientRect (ddrawsink->video_window, &destsurf_rect);
904 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
906 if (ddrawsink->keep_aspect_ratio) {
907 /* center image to dest image keeping aspect ratio */
910 src_rect.bottom = ddrawsink->video_height;
911 src_rect.right = ddrawsink->video_width;
912 gst_directdraw_sink_center_rect (ddrawsink, src_rect, destsurf_rect,
914 gst_directdraw_sink_draw_borders (ddrawsink, destsurf_rect);
916 GST_OBJECT_UNLOCK (ddrawsink);
918 if (ddrawsink->must_recreate_offscreen && ddrawsink->offscreen_surface) {
919 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
920 ddrawsink->offscreen_surface = NULL;
923 /* check for surfaces lost */
924 if (!gst_directdraw_sink_check_primary_surface (ddrawsink) ||
925 !gst_directdraw_sink_check_offscreen_surface (ddrawsink)) {
926 return GST_FLOW_ERROR;
929 if (!GST_IS_DDRAWSURFACE (buf) ||
930 ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
931 /* We are receiving a system memory buffer so we will copy
932 to the memory of our offscreen surface and next blit this surface
933 on the primary surface */
935 guint src_pitch, line;
936 DDSURFACEDESC2 surf_desc;
939 ZeroMemory (&surf_desc, sizeof (surf_desc));
940 surf_desc.dwSize = sizeof (surf_desc);
943 /* Lock the surface */
945 IDirectDrawSurface7_Lock (ddrawsink->offscreen_surface, NULL,
946 (DDSURFACEDESC *) sd, DDLOCK_WAIT, NULL);
948 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
949 "gst_directdraw_sink_show_frame failed locking surface %s",
950 DDErrorString (hRes));
952 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK)
955 return GST_FLOW_ERROR;
958 /* Write each line respecting the destination surface pitch */
959 data = surf_desc.lpSurface;
960 if (ddrawsink->video_height) {
961 src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
962 for (line = 0; line < surf_desc.dwHeight; line++) {
963 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
964 data += surf_desc.lPitch;
968 /* Unlock the surface */
969 hRes = IDirectDrawSurface7_Unlock (ddrawsink->offscreen_surface, NULL);
971 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
972 "gst_directdraw_sink_show_frame failed unlocking surface %s",
973 DDErrorString (hRes));
974 return GST_FLOW_ERROR;
977 /* blit to primary surface ( Blt will scale the video the dest rect surface
979 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
980 ddrawsink->offscreen_surface, NULL, DDBLT_WAIT, NULL);
981 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
982 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
983 "IDirectDrawSurface7_Blt (object's offscreen surface) " "returned %s",
984 DDErrorString (hRes));
987 /* We are receiving a directdraw surface (previously returned by our buffer
988 * pool so we will simply blit it on the primary surface */
989 GstDDrawSurface *surface = NULL;
991 surface = GST_DDRAWSURFACE (buf);
993 /* Unlocking surface before blit */
994 IDirectDrawSurface7_Unlock (surface->surface, NULL);
995 surface->locked = FALSE;
997 /* blit to our primary surface */
998 hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
999 surface->surface, NULL, DDBLT_WAIT, NULL);
1000 if (hRes != DD_OK) /* FIXME: Is it really safe to continue past here ? */
1001 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1002 "IDirectDrawSurface7_Blt (offscreen surface from buffer_alloc) "
1003 "returned %s", DDErrorString (hRes));
1010 gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1011 GstClockTime * start, GstClockTime * end)
1013 GstDirectDrawSink *ddrawsink;
1015 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1017 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1018 *start = GST_BUFFER_TIMESTAMP (buf);
1019 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1020 *end = *start + GST_BUFFER_DURATION (buf);
1022 if (ddrawsink->fps_n > 0) {
1023 *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1029 /* Utility functions */
1031 /* this function fill a DDPIXELFORMAT using Gstreamer caps */
1033 gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink * ddrawsink,
1034 GstCaps * caps, DDPIXELFORMAT * pPixelFormat)
1036 GstStructure *structure = NULL;
1037 gboolean ret = TRUE;
1040 g_return_val_if_fail (pPixelFormat, FALSE);
1041 g_return_val_if_fail (caps, FALSE);
1043 /* init structure */
1044 memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
1045 pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
1047 if (!(structure = gst_caps_get_structure (caps, 0))) {
1048 GST_CAT_ERROR_OBJECT (directdrawsink_debug, ddrawsink,
1049 "can't get structure pointer from caps");
1053 if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
1054 gint depth, bitcount, bitmask, endianness;
1056 pPixelFormat->dwFlags = DDPF_RGB;
1057 ret &= gst_structure_get_int (structure, "bpp", &bitcount);
1058 pPixelFormat->dwRGBBitCount = bitcount;
1059 ret &= gst_structure_get_int (structure, "depth", &depth);
1060 ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
1061 pPixelFormat->dwRBitMask = bitmask;
1062 ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
1063 pPixelFormat->dwGBitMask = bitmask;
1064 ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
1065 pPixelFormat->dwBBitMask = bitmask;
1067 gst_structure_get_int (structure, "endianness", &endianness);
1068 if (endianness == G_BIG_ENDIAN) {
1069 endianness = G_LITTLE_ENDIAN;
1070 pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
1071 pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
1072 pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
1074 } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
1077 pPixelFormat->dwFlags = DDPF_FOURCC;
1078 ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
1079 pPixelFormat->dwFourCC = fourcc;
1081 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1082 "unknown caps name received %" GST_PTR_FORMAT, caps);
1089 /* This function centers the RECT of source surface to
1090 a dest surface and set the result RECT into result */
1092 gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink, RECT src,
1093 RECT dst, RECT * result)
1095 gdouble src_ratio, dst_ratio;
1096 long src_width = src.right;
1097 long src_height = src.bottom;
1098 long dst_width = dst.right - dst.left;
1099 long dst_heigth = dst.bottom - dst.top;
1100 long result_width = 0, result_height = 0;
1102 g_return_if_fail (result != NULL);
1104 src_ratio = (gdouble) src_width / src_height;
1105 dst_ratio = (gdouble) dst_width / dst_heigth;
1107 if (src_ratio > dst_ratio) {
1109 result_height = (long) (dst_width / src_ratio);
1111 result->left = dst.left;
1112 result->right = dst.right;
1113 result->top = dst.top + (dst_heigth - result_height) / 2;
1114 result->bottom = result->top + result_height;
1116 } else if (src_ratio < dst_ratio) {
1118 result_width = (long) (dst_heigth * src_ratio);
1120 result->top = dst.top;
1121 result->bottom = dst.bottom;
1122 result->left = dst.left + (dst_width - result_width) / 2;
1123 result->right = result->left + result_width;
1127 memcpy (result, &dst, sizeof (RECT));
1130 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1131 "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
1132 src_width, src_height, dst_width, dst_heigth,
1133 result->right - result->left, result->bottom - result->top, result->left,
1138 * Get DirectDraw error message.
1140 * Returns: Text representation of the error.
1143 DDErrorString (HRESULT hr)
1146 case DDERR_ALREADYINITIALIZED:
1147 return "DDERR_ALREADYINITIALIZED";
1148 case DDERR_CANNOTATTACHSURFACE:
1149 return "DDERR_CANNOTATTACHSURFACE";
1150 case DDERR_CANNOTDETACHSURFACE:
1151 return "DDERR_CANNOTDETACHSURFACE";
1152 case DDERR_CURRENTLYNOTAVAIL:
1153 return "DDERR_CURRENTLYNOTAVAIL";
1154 case DDERR_EXCEPTION:
1155 return "DDERR_EXCEPTION";
1157 return "DDERR_GENERIC";
1158 case DDERR_HEIGHTALIGN:
1159 return "DDERR_HEIGHTALIGN";
1160 case DDERR_INCOMPATIBLEPRIMARY:
1161 return "DDERR_INCOMPATIBLEPRIMARY";
1162 case DDERR_INVALIDCAPS:
1163 return "DDERR_INVALIDCAPS";
1164 case DDERR_INVALIDCLIPLIST:
1165 return "DDERR_INVALIDCLIPLIST";
1166 case DDERR_INVALIDMODE:
1167 return "DDERR_INVALIDMODE";
1168 case DDERR_INVALIDOBJECT:
1169 return "DDERR_INVALIDOBJECT";
1170 case DDERR_INVALIDPARAMS:
1171 return "DDERR_INVALIDPARAMS";
1172 case DDERR_INVALIDPIXELFORMAT:
1173 return "DDERR_INVALIDPIXELFORMAT";
1174 case DDERR_INVALIDRECT:
1175 return "DDERR_INVALIDRECT";
1176 case DDERR_LOCKEDSURFACES:
1177 return "DDERR_LOCKEDSURFACES";
1179 return "DDERR_NO3D";
1180 case DDERR_NOALPHAHW:
1181 return "DDERR_NOALPHAHW";
1182 case DDERR_NOCLIPLIST:
1183 return "DDERR_NOCLIPLIST";
1184 case DDERR_NOCOLORCONVHW:
1185 return "DDERR_NOCOLORCONVHW";
1186 case DDERR_NOCOOPERATIVELEVELSET:
1187 return "DDERR_NOCOOPERATIVELEVELSET";
1188 case DDERR_NOCOLORKEY:
1189 return "DDERR_NOCOLORKEY";
1190 case DDERR_NOCOLORKEYHW:
1191 return "DDERR_NOCOLORKEYHW";
1192 case DDERR_NODIRECTDRAWSUPPORT:
1193 return "DDERR_NODIRECTDRAWSUPPORT";
1194 case DDERR_NOEXCLUSIVEMODE:
1195 return "DDERR_NOEXCLUSIVEMODE";
1196 case DDERR_NOFLIPHW:
1197 return "DDERR_NOFLIPHW";
1199 return "DDERR_NOGDI";
1200 case DDERR_NOMIRRORHW:
1201 return "DDERR_NOMIRRORHW";
1202 case DDERR_NOTFOUND:
1203 return "DDERR_NOTFOUND";
1204 case DDERR_NOOVERLAYHW:
1205 return "DDERR_NOOVERLAYHW";
1206 case DDERR_NORASTEROPHW:
1207 return "DDERR_NORASTEROPHW";
1208 case DDERR_NOROTATIONHW:
1209 return "DDERR_NOROTATIONHW";
1210 case DDERR_NOSTRETCHHW:
1211 return "DDERR_NOSTRETCHHW";
1212 case DDERR_NOT4BITCOLOR:
1213 return "DDERR_NOT4BITCOLOR";
1214 case DDERR_NOT4BITCOLORINDEX:
1215 return "DDERR_NOT4BITCOLORINDEX";
1216 case DDERR_NOT8BITCOLOR:
1217 return "DDERR_NOT8BITCOLOR";
1218 case DDERR_NOTEXTUREHW:
1219 return "DDERR_NOTEXTUREHW";
1220 case DDERR_NOVSYNCHW:
1221 return "DDERR_NOVSYNCHW";
1222 case DDERR_NOZBUFFERHW:
1223 return "DDERR_NOZBUFFERHW";
1224 case DDERR_NOZOVERLAYHW:
1225 return "DDERR_NOZOVERLAYHW";
1226 case DDERR_OUTOFCAPS:
1227 return "DDERR_OUTOFCAPS";
1228 case DDERR_OUTOFMEMORY:
1229 return "DDERR_OUTOFMEMORY";
1230 case DDERR_OUTOFVIDEOMEMORY:
1231 return "DDERR_OUTOFVIDEOMEMORY";
1232 case DDERR_OVERLAYCANTCLIP:
1233 return "DDERR_OVERLAYCANTCLIP";
1234 case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
1235 return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
1236 case DDERR_PALETTEBUSY:
1237 return "DDERR_PALETTEBUSY";
1238 case DDERR_COLORKEYNOTSET:
1239 return "DDERR_COLORKEYNOTSET";
1240 case DDERR_SURFACEALREADYATTACHED:
1241 return "DDERR_SURFACEALREADYATTACHED";
1242 case DDERR_SURFACEALREADYDEPENDENT:
1243 return "DDERR_SURFACEALREADYDEPENDENT";
1244 case DDERR_SURFACEBUSY:
1245 return "DDERR_SURFACEBUSY";
1246 case DDERR_CANTLOCKSURFACE:
1247 return "DDERR_CANTLOCKSURFACE";
1248 case DDERR_SURFACEISOBSCURED:
1249 return "DDERR_SURFACEISOBSCURED";
1250 case DDERR_SURFACELOST:
1251 return "DDERR_SURFACELOST";
1252 case DDERR_SURFACENOTATTACHED:
1253 return "DDERR_SURFACENOTATTACHED";
1254 case DDERR_TOOBIGHEIGHT:
1255 return "DDERR_TOOBIGHEIGHT";
1256 case DDERR_TOOBIGSIZE:
1257 return "DDERR_TOOBIGSIZE";
1258 case DDERR_TOOBIGWIDTH:
1259 return "DDERR_TOOBIGWIDTH";
1260 case DDERR_UNSUPPORTED:
1261 return "DDERR_UNSUPPORTED";
1262 case DDERR_UNSUPPORTEDFORMAT:
1263 return "DDERR_UNSUPPORTEDFORMAT";
1264 case DDERR_UNSUPPORTEDMASK:
1265 return "DDERR_UNSUPPORTEDMASK";
1266 case DDERR_VERTICALBLANKINPROGRESS:
1267 return "DDERR_VERTICALBLANKINPROGRESS";
1268 case DDERR_WASSTILLDRAWING:
1269 return "DDERR_WASSTILLDRAWING";
1271 return "DDERR_XALIGN";
1272 case DDERR_INVALIDDIRECTDRAWGUID:
1273 return "DDERR_INVALIDDIRECTDRAWGUID";
1274 case DDERR_DIRECTDRAWALREADYCREATED:
1275 return "DDERR_DIRECTDRAWALREADYCREATED";
1276 case DDERR_NODIRECTDRAWHW:
1277 return "DDERR_NODIRECTDRAWHW";
1278 case DDERR_PRIMARYSURFACEALREADYEXISTS:
1279 return "DDERR_PRIMARYSURFACEALREADYEXISTS";
1280 case DDERR_NOEMULATION:
1281 return "DDERR_NOEMULATION";
1282 case DDERR_REGIONTOOSMALL:
1283 return "DDERR_REGIONTOOSMALL";
1284 case DDERR_CLIPPERISUSINGHWND:
1285 return "DDERR_CLIPPERISUSINGHWND";
1286 case DDERR_NOCLIPPERATTACHED:
1287 return "DDERR_NOCLIPPERATTACHED";
1289 return "DDERR_NOHWND";
1290 case DDERR_HWNDSUBCLASSED:
1291 return "DDERR_HWNDSUBCLASSED";
1292 case DDERR_HWNDALREADYSET:
1293 return "DDERR_HWNDALREADYSET";
1294 case DDERR_NOPALETTEATTACHED:
1295 return "DDERR_NOPALETTEATTACHED";
1296 case DDERR_NOPALETTEHW:
1297 return "DDERR_NOPALETTEHW";
1298 case DDERR_BLTFASTCANTCLIP:
1299 return "DDERR_BLTFASTCANTCLIP";
1301 return "DDERR_NOBLTHW";
1302 case DDERR_NODDROPSHW:
1303 return "DDERR_NODDROPSHW";
1304 case DDERR_OVERLAYNOTVISIBLE:
1305 return "DDERR_OVERLAYNOTVISIBLE";
1306 case DDERR_NOOVERLAYDEST:
1307 return "DDERR_NOOVERLAYDEST";
1308 case DDERR_INVALIDPOSITION:
1309 return "DDERR_INVALIDPOSITION";
1310 case DDERR_NOTAOVERLAYSURFACE:
1311 return "DDERR_NOTAOVERLAYSURFACE";
1312 case DDERR_EXCLUSIVEMODEALREADYSET:
1313 return "DDERR_EXCLUSIVEMODEALREADYSET";
1314 case DDERR_NOTFLIPPABLE:
1315 return "DDERR_NOTFLIPPABLE";
1316 case DDERR_CANTDUPLICATE:
1317 return "DDERR_CANTDUPLICATE";
1318 case DDERR_NOTLOCKED:
1319 return "DDERR_NOTLOCKED";
1320 case DDERR_CANTCREATEDC:
1321 return "DDERR_CANTCREATEDC";
1323 return "DDERR_NODC";
1324 case DDERR_WRONGMODE:
1325 return "DDERR_WRONGMODE";
1326 case DDERR_IMPLICITLYCREATED:
1327 return "DDERR_IMPLICITLYCREATED";
1328 case DDERR_NOTPALETTIZED:
1329 return "DDERR_NOTPALETTIZED";
1330 case DDERR_UNSUPPORTEDMODE:
1331 return "DDERR_UNSUPPORTEDMODE";
1332 case DDERR_NOMIPMAPHW:
1333 return "DDERR_NOMIPMAPHW";
1334 case DDERR_INVALIDSURFACETYPE:
1335 return "DDERR_INVALIDSURFACETYPE";
1336 case DDERR_DCALREADYCREATED:
1337 return "DDERR_DCALREADYCREATED";
1338 case DDERR_CANTPAGELOCK:
1339 return "DDERR_CANTPAGELOCK";
1340 case DDERR_CANTPAGEUNLOCK:
1341 return "DDERR_CANTPAGEUNLOCK";
1342 case DDERR_NOTPAGELOCKED:
1343 return "DDERR_NOTPAGELOCKED";
1344 case DDERR_NOTINITIALIZED:
1345 return "DDERR_NOTINITIALIZED";
1347 return "Unknown Error";
1351 gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1353 gboolean bRet = TRUE;
1355 /* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first
1356 * parameter to force Directdraw to use the hardware emulation layer */
1357 hRes = DirectDrawCreateEx ( /*DDCREATE_EMULATIONONLY */ 0,
1358 (void **) &ddrawsink->ddraw_object, &IID_IDirectDraw7, NULL);
1359 if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
1360 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1361 ("Failed to create the DirectDraw object error=%s",
1362 DDErrorString (hRes)), (NULL));
1366 /* set cooperative level */
1367 hRes = IDirectDraw7_SetCooperativeLevel (ddrawsink->ddraw_object,
1368 NULL, DDSCL_NORMAL);
1369 if (hRes != DD_OK) {
1370 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1371 ("Failed to set the set the cooperative level error=%s",
1372 DDErrorString (hRes)), (NULL));
1376 /* setup the clipper object */
1377 hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
1378 &ddrawsink->clipper, NULL);
1380 if (hRes == DD_OK && ddrawsink->video_window)
1381 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1383 /* create our primary surface */
1384 if (!gst_directdraw_sink_check_primary_surface (ddrawsink))
1387 /* directdraw objects are setup */
1388 ddrawsink->setup = TRUE;
1393 static long FAR PASCAL
1394 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1398 LPCREATESTRUCT crs = (LPCREATESTRUCT) lParam;
1399 /* Nail pointer to the video sink down to this window */
1400 SetWindowLongPtr (hWnd, GWLP_USERDATA, (LONG_PTR) crs->lpCreateParams);
1407 case WM_LBUTTONDOWN:
1408 case WM_RBUTTONDOWN:
1409 case WM_MBUTTONDOWN:
1414 GstDirectDrawSink *ddrawsink;
1415 ddrawsink = (GstDirectDrawSink *) GetWindowLongPtr (hWnd, GWLP_USERDATA);
1417 if (G_UNLIKELY (!ddrawsink))
1422 GST_OBJECT_LOCK (ddrawsink);
1423 ddrawsink->out_width = LOWORD (lParam);
1424 ddrawsink->out_height = HIWORD (lParam);
1425 GST_OBJECT_UNLOCK (ddrawsink);
1426 GST_DEBUG_OBJECT (ddrawsink, "Window size is %dx%d", LOWORD (wParam),
1433 gunichar2 wcrep[128];
1434 if (GetKeyNameTextW (lParam, wcrep, 128)) {
1435 gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
1437 if (message == WM_CHAR || message == WM_KEYDOWN)
1438 gst_navigation_send_key_event (GST_NAVIGATION (ddrawsink),
1439 "key-press", utfrep);
1440 if (message == WM_CHAR || message == WM_KEYUP)
1441 gst_navigation_send_key_event (GST_NAVIGATION (ddrawsink),
1442 "key-release", utfrep);
1448 case WM_LBUTTONDOWN:
1450 case WM_RBUTTONDOWN:
1452 case WM_MBUTTONDOWN:
1456 const gchar *action;
1461 action = "mouse-move";
1463 case WM_LBUTTONDOWN:
1465 action = "mouse-button-press";
1469 action = "mouse-button-release";
1471 case WM_RBUTTONDOWN:
1473 action = "mouse-button-press";
1477 action = "mouse-button-release";
1479 case WM_MBUTTONDOWN:
1481 action = "mouse-button-press";
1485 action = "mouse-button-release";
1491 x = LOWORD (lParam);
1492 y = HIWORD (lParam);
1495 GST_DEBUG_OBJECT (ddrawsink, "Mouse moved to %dx%d", x, y);
1497 GST_DEBUG_OBJECT (ddrawsink, "Mouse button %d pressed at %dx%d",
1501 gst_navigation_send_mouse_event (GST_NAVIGATION (ddrawsink),
1502 action, button, x, y);
1512 DestroyWindow (hWnd);
1514 PostQuitMessage (0);
1518 return DefWindowProc (hWnd, message, wParam, lParam);
1522 gst_directdraw_sink_window_thread (GstDirectDrawSink * ddrawsink)
1527 memset (&WndClass, 0, sizeof (WNDCLASS));
1528 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1529 WndClass.hInstance = GetModuleHandle (NULL);
1530 WndClass.lpszClassName = "GStreamer-DirectDraw";
1531 WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
1532 WndClass.cbClsExtra = 0;
1533 WndClass.cbWndExtra = 0;
1534 WndClass.lpfnWndProc = WndProc;
1535 WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
1536 RegisterClass (&WndClass);
1538 ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
1539 "GStreamer-DirectDraw sink default window",
1540 WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
1541 WndClass.hInstance, (LPVOID) ddrawsink);
1542 if (ddrawsink->video_window == NULL)
1545 /* Set the clipper on that window */
1546 IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0, ddrawsink->video_window);
1548 /* signal application we created a window */
1549 gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ddrawsink),
1550 (gulong) ddrawsink->video_window);
1552 ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1554 /* start message loop processing our default window messages */
1555 while (GetMessage (&msg, NULL, 0, 0) != FALSE) {
1556 TranslateMessage (&msg);
1557 DispatchMessage (&msg);
1560 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1561 "our window received WM_QUIT or error.");
1562 /* The window could have changed, if it is not ours anymore we don't
1563 * overwrite the current video window with NULL */
1564 if (ddrawsink->our_video_window) {
1565 GST_OBJECT_LOCK (ddrawsink);
1566 ddrawsink->video_window = NULL;
1567 GST_OBJECT_UNLOCK (ddrawsink);
1574 gst_directdraw_sink_create_default_window (GstDirectDrawSink * ddrawsink)
1576 ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1577 if (ddrawsink->window_created_signal == NULL)
1580 ddrawsink->window_thread = g_thread_create (
1581 (GThreadFunc) gst_directdraw_sink_window_thread, ddrawsink, TRUE, NULL);
1583 if (ddrawsink->window_thread == NULL)
1586 /* wait maximum 10 seconds for windows creating */
1587 if (WaitForSingleObject (ddrawsink->window_created_signal,
1588 10000) != WAIT_OBJECT_0)
1591 CloseHandle (ddrawsink->window_created_signal);
1595 CloseHandle (ddrawsink->window_created_signal);
1596 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1597 ("Error creating our default window"), (NULL));
1603 gst_directdraw_sink_check_primary_surface (GstDirectDrawSink * ddrawsink)
1606 DDSURFACEDESC2 dd_surface_desc;
1609 /* if our primary surface already exist, check if it's not lost */
1610 if (ddrawsink->primary_surface) {
1611 if (IDirectDrawSurface7_IsLost (ddrawsink->primary_surface) == DD_OK) {
1612 /* no problem with our primary surface */
1615 /* our primary surface was lost, try to restore it */
1616 if (IDirectDrawSurface7_Restore (ddrawsink->primary_surface) == DD_OK) {
1617 /* restore is done */
1618 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1619 "Our primary surface" " was restored after lost");
1622 /* failed to restore our primary surface,
1623 * probably because the display mode was changed.
1624 * Release this surface and recreate a new one.
1626 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1627 "Our primary surface"
1628 " was lost and display mode has changed. Destroy and recreate our surface.");
1629 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
1630 ddrawsink->primary_surface = NULL;
1632 /* also release offscreen surface */
1633 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1634 ddrawsink->offscreen_surface = NULL;
1639 /* create our primary surface */
1640 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1641 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1642 dd_surface_desc.dwFlags = DDSD_CAPS;
1643 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1644 sd = &dd_surface_desc;
1646 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1647 &ddrawsink->primary_surface, NULL);
1648 if (hres != DD_OK) {
1649 GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
1650 ("Failed to create our primary surface error=%s", DDErrorString (hres)),
1655 /* attach our clipper object to the new primary surface */
1656 if (ddrawsink->clipper) {
1657 hres = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
1658 ddrawsink->clipper);
1665 gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink * ddrawsink)
1667 DDSURFACEDESC2 dd_surface_desc;
1671 /* if our offscreen surface already exist, check if it's not lost */
1672 if (ddrawsink->offscreen_surface) {
1673 if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK) {
1674 /* no problem with our offscreen surface */
1677 /* our offscreen surface was lost, try to restore it */
1678 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
1679 /* restore is done */
1680 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1681 "Our offscreen surface" " was restored after lost");
1684 /* failed to restore our offscreen surface,
1685 * probably because the display mode was changed.
1686 * Release this surface and recreate a new one.
1688 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
1689 "Our offscreen surface"
1690 " was lost and display mode has changed. Destroy and recreate our surface.");
1691 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
1692 ddrawsink->offscreen_surface = NULL;
1697 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1698 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1699 dd_surface_desc.dwFlags =
1700 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1701 dd_surface_desc.dwHeight = ddrawsink->video_height;
1702 dd_surface_desc.dwWidth = ddrawsink->video_width;
1703 memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
1704 sizeof (DDPIXELFORMAT));
1706 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1707 sd = &dd_surface_desc;
1709 IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, (DDSURFACEDESC *) sd,
1710 &ddrawsink->offscreen_surface, NULL);
1711 if (hres != DD_OK) {
1712 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1713 "create_ddraw_surface:CreateSurface (offscreen surface for buffer_pool) failed %s",
1714 DDErrorString (hres));
1718 ddrawsink->must_recreate_offscreen = FALSE;
1724 gst_directdraw_sink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1726 gint order = 0, binary;
1730 dwRBitMask | lpddpfPixelFormat->dwGBitMask | lpddpfPixelFormat->
1731 dwBBitMask | lpddpfPixelFormat->dwRGBAlphaBitMask;
1732 while (binary != 0) {
1733 if ((binary % 2) == 1)
1735 binary = binary >> 1;
1740 static HRESULT WINAPI
1741 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1743 GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1744 GstCaps *format_caps = NULL;
1745 LPDDSURFACEDESC2 sd;
1747 if (!ddrawsink || !lpDDSurfaceDesc)
1748 return DDENUMRET_CANCEL;
1750 sd = (LPDDSURFACEDESC2) lpDDSurfaceDesc;
1751 if ((sd->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
1752 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1753 "Display mode found with DDSD_PIXELFORMAT not set");
1754 return DDENUMRET_OK;
1757 if ((sd->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1758 return DDENUMRET_OK;
1760 format_caps = gst_directdraw_sink_create_caps_from_surfacedesc (sd);
1763 gst_caps_append (ddrawsink->caps, format_caps);
1766 return DDENUMRET_OK;
1770 gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc)
1772 GstCaps *caps = NULL;
1773 gint endianness = G_LITTLE_ENDIAN;
1776 if ((desc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1779 depth = gst_directdraw_sink_get_depth (&desc->ddpfPixelFormat);
1781 if (desc->ddpfPixelFormat.dwRGBBitCount == 24 ||
1782 desc->ddpfPixelFormat.dwRGBBitCount == 32) {
1783 /* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
1784 endianness = G_BIG_ENDIAN;
1785 desc->ddpfPixelFormat.dwRBitMask =
1786 GUINT32_TO_BE (desc->ddpfPixelFormat.dwRBitMask);
1787 desc->ddpfPixelFormat.dwGBitMask =
1788 GUINT32_TO_BE (desc->ddpfPixelFormat.dwGBitMask);
1789 desc->ddpfPixelFormat.dwBBitMask =
1790 GUINT32_TO_BE (desc->ddpfPixelFormat.dwBBitMask);
1791 if (desc->ddpfPixelFormat.dwRGBBitCount == 24) {
1792 desc->ddpfPixelFormat.dwRBitMask >>= 8;
1793 desc->ddpfPixelFormat.dwGBitMask >>= 8;
1794 desc->ddpfPixelFormat.dwBBitMask >>= 8;
1798 caps = gst_caps_new_simple ("video/x-raw-rgb",
1799 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1800 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1801 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
1802 "bpp", G_TYPE_INT, desc->ddpfPixelFormat.dwRGBBitCount,
1803 "depth", G_TYPE_INT, depth,
1804 "endianness", G_TYPE_INT, endianness,
1805 "red_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwRBitMask,
1806 "green_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwGBitMask,
1807 "blue_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwBBitMask, NULL);
1813 gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1815 HRESULT hRes = S_OK;
1816 DDCAPS ddcaps_hardware;
1817 DDCAPS ddcaps_emulation;
1818 GstCaps *format_caps = NULL;
1820 ddrawsink->caps = gst_caps_new_empty ();
1821 if (!ddrawsink->caps)
1824 /* get hardware caps */
1825 ddcaps_hardware.dwSize = sizeof (DDCAPS);
1826 ddcaps_emulation.dwSize = sizeof (DDCAPS);
1827 IDirectDraw7_GetCaps (ddrawsink->ddraw_object, &ddcaps_hardware,
1830 /* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw
1831 * emulation layer can do it */
1832 if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
1833 DDSURFACEDESC2 surface_desc;
1836 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1837 "hardware doesn't support blit from one colorspace to another one. "
1838 "so we will create a caps with only the current display mode");
1840 /* save blit caps */
1841 ddrawsink->can_blit_between_colorspace = FALSE;
1843 surface_desc.dwSize = sizeof (surface_desc);
1846 IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object,
1847 (DDSURFACEDESC *) sd);
1848 if (hRes != DD_OK) {
1849 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1850 ("Error getting the current display mode error=%s",
1851 DDErrorString (hRes)), (NULL));
1856 gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
1858 gst_caps_append (ddrawsink->caps, format_caps);
1861 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1862 gst_caps_to_string (ddrawsink->caps));
1863 return ddrawsink->caps;
1866 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1867 "the hardware can blit from one colorspace to another, "
1868 "then enumerate the colorspace supported by the hardware");
1870 /* save blit caps */
1871 ddrawsink->can_blit_between_colorspace = TRUE;
1873 /* enumerate display modes exposed by directdraw object
1874 to know supported RGB modes */
1876 IDirectDraw7_EnumDisplayModes (ddrawsink->ddraw_object,
1877 DDEDM_REFRESHRATES, NULL, ddrawsink, EnumModesCallback2);
1878 if (hRes != DD_OK) {
1879 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1880 ("Error enumerating display modes error=%s", DDErrorString (hRes)),
1886 if (gst_caps_is_empty (ddrawsink->caps)) {
1887 gst_caps_unref (ddrawsink->caps);
1888 ddrawsink->caps = NULL;
1889 GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
1890 ("No supported caps found."), (NULL));
1894 /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s",
1895 * gst_caps_to_string (ddrawsink->caps)); */
1897 return ddrawsink->caps;
1900 /* Creates miniobject and our internal surface */
1901 static GstDDrawSurface *
1902 gst_directdraw_sink_surface_create (GstDirectDrawSink * ddrawsink,
1903 GstCaps * caps, size_t size)
1905 GstDDrawSurface *surface = NULL;
1906 GstStructure *structure = NULL;
1912 DDSURFACEDESC2 surf_desc, surf_lock_desc;
1914 g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1916 /*init structures */
1917 memset (&surf_desc, 0, sizeof (surf_desc));
1918 memset (&surf_lock_desc, 0, sizeof (surf_desc));
1919 surf_desc.dwSize = sizeof (surf_desc);
1920 surf_lock_desc.dwSize = sizeof (surf_lock_desc);
1922 /*create miniobject and initialize it */
1923 surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1924 surface->locked = FALSE;
1926 structure = gst_caps_get_structure (caps, 0);
1927 if (!gst_structure_get_int (structure, "width", &surface->width) ||
1928 !gst_structure_get_int (structure, "height", &surface->height)) {
1929 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1930 "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
1933 pitch = GST_ROUND_UP_8 (size / surface->height);
1934 if (!gst_ddrawvideosink_get_format_from_caps (ddrawsink, caps,
1935 &surface->dd_pixel_format)) {
1936 GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
1937 "failed getting pixel format from caps %" GST_PTR_FORMAT, caps);
1940 /* disable return of directdraw surface to buffer alloc because actually I
1941 * have no solution to handle display mode changes. The problem is that when
1942 * the display mode is changed surface's memory is freed then the upstream
1943 * filter would crash trying to write to this memory. Directdraw has a system
1944 * lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
1945 * when a surface memory is locked but we need to disable this lock to return
1946 * multiple buffers (surfaces) and do not lock directdraw API calls.
1949 /* if (ddrawsink->ddraw_object) {*/
1950 /* Creating an internal surface which will be used as GstBuffer, we used
1951 the detected pixel format and video dimensions */
1953 surf_desc.ddsCaps.dwCaps =
1954 DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1956 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1957 surf_desc.dwHeight = surface->height;
1958 surf_desc.dwWidth = surface->width;
1959 memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1960 sizeof (DDPIXELFORMAT));
1962 hRes = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1963 &surface->surface, NULL);
1964 if (hRes != DD_OK) {
1965 goto surface_pitch_bad;
1968 /* Locking the surface to acquire the memory pointer.
1969 Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
1970 if directdraw api is used while a buffer is lock */
1972 hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1973 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1974 if (hRes == DDERR_SURFACELOST) {
1975 IDirectDrawSurface7_Restore (surface->surface);
1978 surface->locked = TRUE;
1980 if (surf_lock_desc.lPitch != pitch) {
1981 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1982 "DDraw stride/pitch %ld isn't as expected value %d, let's continue allocating a system memory buffer.",
1983 surf_lock_desc.lPitch, pitch);
1985 /*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
1986 hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
1987 goto surface_pitch_bad;
1989 GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
1990 GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
1991 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
1992 "allocating a surface of %d bytes (stride=%ld)\n", size,
1993 surf_lock_desc.lPitch);
1997 GST_BUFFER (surface)->malloc_data = g_malloc (size);
1998 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
1999 GST_BUFFER_SIZE (surface) = size;
2000 surface->surface = NULL;
2001 GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
2002 "allocating a system memory buffer of %d bytes", size);
2006 /* Keep a ref to our sink */
2007 surface->ddrawsink = gst_object_ref (ddrawsink);
2012 /* We are called from the finalize method of miniobject, the object will be
2013 * destroyed so we just have to clean our internal stuff */
2015 gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
2016 GstDDrawSurface * surface)
2018 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
2020 /* Release our internal surface */
2021 if (surface->surface) {
2022 if (surface->locked) {
2023 IDirectDrawSurface7_Unlock (surface->surface, NULL);
2024 surface->locked = FALSE;
2026 IDirectDrawSurface7_Release (surface->surface);
2027 surface->surface = NULL;
2030 if (GST_BUFFER (surface)->malloc_data) {
2031 g_free (GST_BUFFER (surface)->malloc_data);
2032 GST_BUFFER (surface)->malloc_data = NULL;
2035 if (!surface->ddrawsink) {
2039 /* Release the ref to our sink */
2040 surface->ddrawsink = NULL;
2041 gst_object_unref (ddrawsink);
2046 GST_WARNING ("no sink found in surface");
2051 gst_directdraw_sink_surface_check (GstDirectDrawSink * ddrawsink,
2052 GstDDrawSurface * surface)
2054 if (!surface->surface)
2055 return TRUE; /* system memory buffer */
2057 if (IDirectDrawSurface7_IsLost (surface->surface) == DD_OK) {
2058 /* no problem with this surface */
2061 /* this surface was lost, try to restore it */
2062 if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
2063 /* restore is done */
2064 GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink, "A surface from our"
2065 " bufferpool was restored after lost");
2074 gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
2076 g_mutex_lock (ddrawsink->pool_lock);
2077 while (ddrawsink->buffer_pool) {
2078 GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
2080 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
2081 ddrawsink->buffer_pool);
2082 gst_directdraw_sink_surface_destroy (ddrawsink, surface);
2083 gst_buffer_unref (GST_BUFFER_CAST (surface));
2085 g_mutex_unlock (ddrawsink->pool_lock);
2089 gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink)
2091 /* Post quit message and wait for our event window thread */
2092 if (ddrawsink->video_window && ddrawsink->our_video_window)
2093 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
2095 if (ddrawsink->window_thread) {
2096 g_thread_join (ddrawsink->window_thread);
2097 ddrawsink->window_thread = NULL;
2100 if (ddrawsink->buffer_pool) {
2101 gst_directdraw_sink_bufferpool_clear (ddrawsink);
2102 ddrawsink->buffer_pool = NULL;
2105 if (ddrawsink->offscreen_surface) {
2106 IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
2107 ddrawsink->offscreen_surface = NULL;
2110 if (ddrawsink->clipper) {
2111 IDirectDrawClipper_Release (ddrawsink->clipper);
2112 ddrawsink->clipper = NULL;
2115 if (ddrawsink->primary_surface) {
2116 IDirectDrawSurface7_Release (ddrawsink->primary_surface);
2117 ddrawsink->primary_surface = NULL;
2120 if (ddrawsink->ddraw_object) {
2121 IDirectDraw7_Release (ddrawsink->ddraw_object);
2122 ddrawsink->ddraw_object = NULL;
2125 if (ddrawsink->last_buffer) {
2126 gst_buffer_unref (ddrawsink->last_buffer);
2127 ddrawsink->last_buffer = NULL;
2130 ddrawsink->setup = FALSE;