2 * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
4 * Based on directfb video sink
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include "gstdirectdrawsink.h"
36 GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
37 #define GST_CAT_DEFAULT directdrawsink_debug
39 /* elementfactory information */
40 static const GstElementDetails gst_directdrawsink_details =
41 GST_ELEMENT_DETAILS ("Video Sink (DIRECTDRAW)",
43 "Output to a video card via DIRECTDRAW",
44 "Sebastien Moutte <sebastien@moutte.net>");
46 GST_BOILERPLATE (GstDirectDrawSink, gst_directdrawsink, GstVideoSink,
49 static void gst_directdrawsink_finalize (GObject * object);
51 static void gst_directdrawsink_set_property (GObject * object,
52 guint prop_id, const GValue * value, GParamSpec * pspec);
53 static void gst_directdrawsink_get_property (GObject * object,
54 guint prop_id, GValue * value, GParamSpec * pspec);
56 static GstCaps *gst_directdrawsink_get_caps (GstBaseSink * bsink);
57 static gboolean gst_directdrawsink_set_caps (GstBaseSink * bsink,
60 static GstStateChangeReturn
61 gst_directdrawsink_change_state (GstElement * element,
62 GstStateChange transition);
65 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
66 guint size, GstCaps * caps, GstBuffer ** buf);
69 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
70 GstClockTime * start, GstClockTime * end);
73 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf);
75 static gboolean gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink);
76 static gboolean gst_directdrawsink_create_default_window (GstDirectDrawSink *
78 static gboolean gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink *
81 static GstCaps *gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink *
84 static void gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink);
85 static void gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink);
88 /*surfaces management functions*/
90 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
91 GstDDrawSurface * surface);
93 static GstDDrawSurface *gst_directdrawsink_surface_create (GstDirectDrawSink *
94 ddrawsink, GstCaps * caps, size_t size);
96 static GstStaticPadTemplate directdrawsink_sink_factory =
97 GST_STATIC_PAD_TEMPLATE ("sink",
100 GST_STATIC_CAPS ("video/x-raw-rgb, "
101 "bpp = (int) { 8, 16, 24, 32 }, "
102 "depth = (int) { 0, 8, 16, 24, 32 }, "
103 "endianness = (int) LITTLE_ENDIAN, "
104 "framerate = (fraction) [ 0, MAX ], "
105 "width = (int) [ 1, MAX ], "
106 "height = (int) [ 1, MAX ]"
109 "framerate = (fraction) [ 0, MAX ], "
110 "width = (int) [ 1, MAX ], "
111 "height = (int) [ 1, MAX ], "
112 "format = (fourcc) { YUY2, UYVY, YVU9, YV12, AYUV }")
121 PROP_KEEP_ASPECT_RATIO
124 /* Utility functions */
126 gst_ddrawvideosink_get_format_from_caps (GstCaps * caps,
127 DDPIXELFORMAT * pPixelFormat)
129 GstStructure *structure = NULL;
133 g_return_val_if_fail (pPixelFormat, FALSE);
134 g_return_val_if_fail (caps, FALSE);
137 memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
138 pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
140 if (!(structure = gst_caps_get_structure (caps, 0)))
143 if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
144 gint depth, bitcount, bitmask;
146 pPixelFormat->dwFlags = DDPF_RGB;
147 ret &= gst_structure_get_int (structure, "bpp", &bitcount);
148 pPixelFormat->dwRGBBitCount = bitcount;
149 ret &= gst_structure_get_int (structure, "depth", &depth);
150 ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
151 pPixelFormat->dwRBitMask = bitmask;
152 ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
153 pPixelFormat->dwGBitMask = bitmask;
154 ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
155 pPixelFormat->dwBBitMask = bitmask;
156 } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
159 pPixelFormat->dwFlags = DDPF_FOURCC;
160 ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
161 pPixelFormat->dwFourCC = fourcc;
163 GST_CAT_WARNING (directdrawsink_debug,
164 "unknown caps name received %" GST_PTR_FORMAT, caps);
173 gst_ddrawvideosink_get_caps_from_format (DDPIXELFORMAT pixel_format)
175 GstCaps *caps = NULL;
179 if ((pixel_format.dwFlags & DDPF_RGB) == DDPF_RGB) {
180 bpp = pixel_format.dwRGBBitCount;
184 if ((pixel_format.dwFlags & DDPF_ALPHAPREMULT) == DDPF_ALPHAPREMULT)
189 caps = gst_caps_new_simple ("video/x-raw-rgb",
190 "bpp", G_TYPE_INT, bpp,
191 "depth", G_TYPE_INT, depth,
192 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
195 if ((pixel_format.dwFlags & DDPF_YUV) == DDPF_YUV) {
196 fourcc = pixel_format.dwFourCC;
197 caps = gst_caps_new_simple ("video/x-raw-yuv",
198 "format", GST_TYPE_FOURCC, fourcc, NULL);
201 g_assert (caps != NULL);
208 gst_directdrawsink_center_rect (RECT src, RECT dst, RECT * result)
210 gdouble src_ratio, dst_ratio;
211 long src_width = src.right;
212 long src_height = src.bottom;
213 long dst_width = dst.right - dst.left;
214 long dst_heigth = dst.bottom - dst.top;
215 long result_width = 0, result_height = 0;
217 g_return_if_fail (result != NULL);
219 src_ratio = (gdouble) src_width / src_height;
220 dst_ratio = (gdouble) dst_width / dst_heigth;
222 if (src_ratio > dst_ratio) {
224 result_height = (long) (dst_width / src_ratio);
226 result->left = dst.left;
227 result->right = dst.right;
228 result->top = dst.top + (dst_heigth - result_height) / 2;
229 result->bottom = result->top + result_height;
231 } else if (src_ratio < dst_ratio) {
233 result_width = (long) (dst_heigth * src_ratio);
235 result->top = dst.top;
236 result->bottom = dst.bottom;
237 result->left = dst.left + (dst_width - result_width) / 2;
238 result->right = result->left + result_width;
242 memcpy (result, &dst, sizeof (RECT));
245 GST_CAT_INFO (directdrawsink_debug,
246 "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
247 src_width, src_height, dst_width, dst_heigth,
248 result->right - result->left, result->bottom - result->top, result->left,
252 /*subclass of GstBuffer which manages surfaces lifetime*/
254 gst_ddrawsurface_finalize (GstDDrawSurface * surface)
256 GstDirectDrawSink *ddrawsink = NULL;
258 g_return_if_fail (surface != NULL);
260 ddrawsink = surface->ddrawsink;
264 /* If our geometry changed we can't reuse that image. */
265 if ((surface->width != ddrawsink->video_width) ||
266 (surface->height != ddrawsink->video_height) ||
267 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
268 sizeof (DDPIXELFORMAT)) != 0)
270 GST_CAT_INFO (directdrawsink_debug,
271 "destroy image as its size changed %dx%d vs current %dx%d",
272 surface->width, surface->height, ddrawsink->video_width,
273 ddrawsink->video_height);
274 gst_directdrawsink_surface_destroy (ddrawsink, surface);
277 /* In that case we can reuse the image and add it to our image pool. */
278 GST_CAT_INFO (directdrawsink_debug, "recycling image in pool");
280 /* need to increment the refcount again to recycle */
281 gst_buffer_ref (GST_BUFFER (surface));
283 g_mutex_lock (ddrawsink->pool_lock);
284 ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
285 g_mutex_unlock (ddrawsink->pool_lock);
290 GST_CAT_WARNING (directdrawsink_debug, "no sink found");
295 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
297 surface->surface = NULL;
300 surface->ddrawsink = NULL;
301 surface->locked = FALSE;
302 surface->system_memory = FALSE;
303 memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
307 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
309 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
311 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
312 gst_ddrawsurface_finalize;
316 gst_ddrawsurface_get_type (void)
318 static GType _gst_ddrawsurface_type;
320 if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
321 static const GTypeInfo ddrawsurface_info = {
322 sizeof (GstBufferClass),
325 gst_ddrawsurface_class_init,
328 sizeof (GstDDrawSurface),
330 (GInstanceInitFunc) gst_ddrawsurface_init,
333 _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
334 "GstDDrawSurface", &ddrawsurface_info, 0);
336 return _gst_ddrawsurface_type;
339 /* FIXME: this is problematic if there is more than one sink instance at the
340 * same time, surely there exists a better solution than this? */
341 /* static GstDirectDrawSink *global_ddrawsink = NULL; */
344 gst_directdrawsink_get_type (void)
346 static GType directdrawsink_type = 0;
348 if (!directdrawsink_type) {
349 static const GTypeInfo directdrawsink_info = {
350 sizeof (GstDirectDrawSinkClass),
351 gst_directdrawsink_base_init,
353 (GClassInitFunc) gst_directdrawsink_class_init,
356 sizeof (GstDirectDrawSink),
358 (GInstanceInitFunc) gst_directdrawsink_init,
361 directdrawsink_type =
362 g_type_register_static (GST_TYPE_VIDEO_SINK, "GstDirectDrawSink",
363 &directdrawsink_info, 0);
366 return directdrawsink_type;
370 gst_directdrawsink_base_init (gpointer g_class)
372 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
374 gst_element_class_set_details (element_class, &gst_directdrawsink_details);
376 gst_element_class_add_pad_template (element_class,
377 gst_static_pad_template_get (&directdrawsink_sink_factory));
381 gst_directdrawsink_class_init (GstDirectDrawSinkClass * klass)
383 GObjectClass *gobject_class;
384 GstElementClass *gstelement_class;
385 GstBaseSinkClass *gstbasesink_class;
387 gobject_class = (GObjectClass *) klass;
388 gstbasesink_class = (GstBaseSinkClass *) klass;
389 gstelement_class = (GstElementClass *) klass;
391 GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
394 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdrawsink_finalize);
396 gobject_class->get_property =
397 GST_DEBUG_FUNCPTR (gst_directdrawsink_get_property);
398 gobject_class->set_property =
399 GST_DEBUG_FUNCPTR (gst_directdrawsink_set_property);
401 gstelement_class->change_state =
402 GST_DEBUG_FUNCPTR (gst_directdrawsink_change_state);
403 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_get_caps);
404 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_set_caps);
405 gstbasesink_class->preroll =
406 GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
407 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
409 gstbasesink_class->get_times =
410 GST_DEBUG_FUNCPTR (gst_directdrawsink_get_times);
411 gstbasesink_class->buffer_alloc =
412 GST_DEBUG_FUNCPTR (gst_directdrawsink_buffer_alloc);
414 /*install properties */
415 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FULLSCREEN,
416 g_param_spec_boolean ("fullscreen", "fullscreen",
417 "boolean to activate fullscreen", FALSE, G_PARAM_READWRITE));
419 /*extern window where we will display the video */
420 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WINDOW,
421 g_param_spec_long ("window", "Window",
422 "The target window for video", G_MINLONG, G_MAXLONG, 0,
425 /*extern surface where we will blit the video */
426 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SURFACE,
427 g_param_spec_pointer ("surface", "Surface",
428 "The target surface for video", G_PARAM_WRITABLE));
430 /*setup aspect ratio mode */
431 g_object_class_install_property (G_OBJECT_CLASS (klass),
432 PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("keep-aspect-ratio",
433 "keep-aspect-ratio", "boolean to video keep aspect ratio", FALSE,
436 /*should add a color_key property to permit applications to define the color used for overlays */
440 gst_directdrawsink_set_property (GObject * object, guint prop_id,
441 const GValue * value, GParamSpec * pspec)
443 GstDirectDrawSink *ddrawsink;
445 ddrawsink = GST_DIRECTDRAW_SINK (object);
449 ddrawsink->extern_surface = g_value_get_pointer (value);
452 ddrawsink->video_window = (HWND) g_value_get_long (value);
453 ddrawsink->resize_window = FALSE;
455 case PROP_FULLSCREEN:
456 /*ddrawsink->fullscreen = g_value_get_boolean (value); not working .... */
458 case PROP_KEEP_ASPECT_RATIO:
459 ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
462 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468 gst_directdrawsink_get_property (GObject * object, guint prop_id,
469 GValue * value, GParamSpec * pspec)
471 GstDirectDrawSink *ddrawsink;
473 ddrawsink = GST_DIRECTDRAW_SINK (object);
476 case PROP_FULLSCREEN:
477 g_value_set_boolean (value, ddrawsink->fullscreen);
479 case PROP_KEEP_ASPECT_RATIO:
480 g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
483 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
489 gst_directdrawsink_finalize (GObject * object)
491 GstDirectDrawSink *ddrawsink;
493 ddrawsink = GST_DIRECTDRAW_SINK (object);
495 if (ddrawsink->pool_lock) {
496 g_mutex_free (ddrawsink->pool_lock);
497 ddrawsink->pool_lock = NULL;
499 if (ddrawsink->setup) {
500 gst_directdrawsink_cleanup (ddrawsink);
505 gst_directdrawsink_init (GstDirectDrawSink * ddrawsink,
506 GstDirectDrawSinkClass * g_class)
508 /*init members variables */
509 ddrawsink->ddraw_object = NULL;
510 ddrawsink->primary_surface = NULL;
511 ddrawsink->overlays = NULL;
512 ddrawsink->clipper = NULL;
513 ddrawsink->extern_surface = NULL;
515 /*video default values */
516 ddrawsink->video_height = 0;
517 ddrawsink->video_width = 0;
518 ddrawsink->fps_n = 0;
519 ddrawsink->fps_d = 0;
521 memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
523 ddrawsink->caps = NULL;
525 ddrawsink->window_thread = NULL;
527 ddrawsink->bUseOverlay = FALSE;
528 ddrawsink->color_key = 0; /*need to be a public property and may be we can enable overlays when this property is set ... */
530 ddrawsink->fullscreen = FALSE;
531 ddrawsink->setup = FALSE;
533 ddrawsink->display_modes = NULL;
534 ddrawsink->buffer_pool = NULL;
536 ddrawsink->resize_window = TRUE; /*resize only our internal window to the video size */
538 ddrawsink->pool_lock = g_mutex_new ();
540 ddrawsink->keep_aspect_ratio = TRUE;
541 /* ddrawsink->can_blit = TRUE;*/
545 gst_directdrawsink_get_caps (GstBaseSink * bsink)
547 GstDirectDrawSink *ddrawsink;
548 GstCaps *caps = NULL;
550 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
552 if (!ddrawsink->setup) {
553 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
556 GST_CAT_INFO (directdrawsink_debug,
557 "getcaps called and we are not setup yet, " "returning template %"
558 GST_PTR_FORMAT, caps);
560 /*if (ddrawsink->extern_surface) {
561 * We are not rendering to our own surface, returning this surface's
563 GST_WARNING ("using extern surface");
564 caps = gst_ddrawvideosink_get_caps_from_format (ddrawsink->dd_pixel_format);
567 /* i think we can't really use the format of the extern surface as the application owning the surface doesn't know
568 the format we will render. But we need to use overlays to overlay any format on the extern surface */
569 caps = gst_caps_ref (ddrawsink->caps);
576 gst_directdrawsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
578 GstDirectDrawSink *ddrawsink;
579 GstStructure *structure = NULL;
583 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
585 structure = gst_caps_get_structure (caps, 0);
589 ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
590 ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
592 fps = gst_structure_get_value (structure, "framerate");
593 ret &= (fps != NULL);
596 gst_ddrawvideosink_get_format_from_caps (caps,
597 &ddrawsink->dd_pixel_format);
602 ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
603 ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
605 if (ddrawsink->video_window && ddrawsink->resize_window) {
606 SetWindowPos (ddrawsink->video_window, NULL,
607 0, 0, ddrawsink->video_width + (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
608 ddrawsink->video_height + GetSystemMetrics (SM_CYCAPTION) +
609 (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
612 /*create overlays flipping chain */
613 ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
614 if (!ret && ddrawsink->bUseOverlay) {
615 GST_CAT_WARNING (directdrawsink_debug,
616 "Can not create overlay surface, reverting to no overlay display");
617 ddrawsink->bUseOverlay = FALSE;
618 ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
623 /*could not create draw surfaces even with fallback, so leave
625 ddrawsink->bUseOverlay = TRUE;
628 GST_CAT_ERROR (directdrawsink_debug, "Can not create ddraw surface");
633 static GstStateChangeReturn
634 gst_directdrawsink_change_state (GstElement * element,
635 GstStateChange transition)
637 GstDirectDrawSink *ddrawsink;
639 ddrawsink = GST_DIRECTDRAW_SINK (element);
641 switch (transition) {
642 case GST_STATE_CHANGE_NULL_TO_READY:
643 if (ddrawsink->video_window == NULL && ddrawsink->extern_surface == NULL)
644 if (!gst_directdrawsink_create_default_window (ddrawsink))
645 return GST_STATE_CHANGE_FAILURE;
647 if (!gst_directdrawsink_setup_ddraw (ddrawsink))
648 return GST_STATE_CHANGE_FAILURE;
650 if (!(ddrawsink->caps = gst_directdrawsink_get_ddrawcaps (ddrawsink)))
651 return GST_STATE_CHANGE_FAILURE;
654 case GST_STATE_CHANGE_READY_TO_PAUSED:
656 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
658 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
660 case GST_STATE_CHANGE_PAUSED_TO_READY:
662 ddrawsink->fps_n = 0;
663 ddrawsink->fps_d = 1;
664 ddrawsink->video_width = 0;
665 ddrawsink->video_height = 0;
667 if (ddrawsink->buffer_pool)
668 gst_directdrawsink_bufferpool_clear (ddrawsink);
671 case GST_STATE_CHANGE_READY_TO_NULL:
673 if (ddrawsink->setup)
674 gst_directdrawsink_cleanup (ddrawsink);
679 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
683 * Get DirectDraw error message.
685 * Returns: Text representation of the error.
688 DDErrorString (HRESULT hr)
691 case DDERR_ALREADYINITIALIZED:
692 return "DDERR_ALREADYINITIALIZED";
693 case DDERR_CANNOTATTACHSURFACE:
694 return "DDERR_CANNOTATTACHSURFACE";
695 case DDERR_CANNOTDETACHSURFACE:
696 return "DDERR_CANNOTDETACHSURFACE";
697 case DDERR_CURRENTLYNOTAVAIL:
698 return "DDERR_CURRENTLYNOTAVAIL";
699 case DDERR_EXCEPTION:
700 return "DDERR_EXCEPTION";
702 return "DDERR_GENERIC";
703 case DDERR_HEIGHTALIGN:
704 return "DDERR_HEIGHTALIGN";
705 case DDERR_INCOMPATIBLEPRIMARY:
706 return "DDERR_INCOMPATIBLEPRIMARY";
707 case DDERR_INVALIDCAPS:
708 return "DDERR_INVALIDCAPS";
709 case DDERR_INVALIDCLIPLIST:
710 return "DDERR_INVALIDCLIPLIST";
711 case DDERR_INVALIDMODE:
712 return "DDERR_INVALIDMODE";
713 case DDERR_INVALIDOBJECT:
714 return "DDERR_INVALIDOBJECT";
715 case DDERR_INVALIDPARAMS:
716 return "DDERR_INVALIDPARAMS";
717 case DDERR_INVALIDPIXELFORMAT:
718 return "DDERR_INVALIDPIXELFORMAT";
719 case DDERR_INVALIDRECT:
720 return "DDERR_INVALIDRECT";
721 case DDERR_LOCKEDSURFACES:
722 return "DDERR_LOCKEDSURFACES";
725 case DDERR_NOALPHAHW:
726 return "DDERR_NOALPHAHW";
727 case DDERR_NOCLIPLIST:
728 return "DDERR_NOCLIPLIST";
729 case DDERR_NOCOLORCONVHW:
730 return "DDERR_NOCOLORCONVHW";
731 case DDERR_NOCOOPERATIVELEVELSET:
732 return "DDERR_NOCOOPERATIVELEVELSET";
733 case DDERR_NOCOLORKEY:
734 return "DDERR_NOCOLORKEY";
735 case DDERR_NOCOLORKEYHW:
736 return "DDERR_NOCOLORKEYHW";
737 case DDERR_NODIRECTDRAWSUPPORT:
738 return "DDERR_NODIRECTDRAWSUPPORT";
739 case DDERR_NOEXCLUSIVEMODE:
740 return "DDERR_NOEXCLUSIVEMODE";
742 return "DDERR_NOFLIPHW";
744 return "DDERR_NOGDI";
745 case DDERR_NOMIRRORHW:
746 return "DDERR_NOMIRRORHW";
748 return "DDERR_NOTFOUND";
749 case DDERR_NOOVERLAYHW:
750 return "DDERR_NOOVERLAYHW";
751 case DDERR_NORASTEROPHW:
752 return "DDERR_NORASTEROPHW";
753 case DDERR_NOROTATIONHW:
754 return "DDERR_NOROTATIONHW";
755 case DDERR_NOSTRETCHHW:
756 return "DDERR_NOSTRETCHHW";
757 case DDERR_NOT4BITCOLOR:
758 return "DDERR_NOT4BITCOLOR";
759 case DDERR_NOT4BITCOLORINDEX:
760 return "DDERR_NOT4BITCOLORINDEX";
761 case DDERR_NOT8BITCOLOR:
762 return "DDERR_NOT8BITCOLOR";
763 case DDERR_NOTEXTUREHW:
764 return "DDERR_NOTEXTUREHW";
765 case DDERR_NOVSYNCHW:
766 return "DDERR_NOVSYNCHW";
767 case DDERR_NOZBUFFERHW:
768 return "DDERR_NOZBUFFERHW";
769 case DDERR_NOZOVERLAYHW:
770 return "DDERR_NOZOVERLAYHW";
771 case DDERR_OUTOFCAPS:
772 return "DDERR_OUTOFCAPS";
773 case DDERR_OUTOFMEMORY:
774 return "DDERR_OUTOFMEMORY";
775 case DDERR_OUTOFVIDEOMEMORY:
776 return "DDERR_OUTOFVIDEOMEMORY";
777 case DDERR_OVERLAYCANTCLIP:
778 return "DDERR_OVERLAYCANTCLIP";
779 case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
780 return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
781 case DDERR_PALETTEBUSY:
782 return "DDERR_PALETTEBUSY";
783 case DDERR_COLORKEYNOTSET:
784 return "DDERR_COLORKEYNOTSET";
785 case DDERR_SURFACEALREADYATTACHED:
786 return "DDERR_SURFACEALREADYATTACHED";
787 case DDERR_SURFACEALREADYDEPENDENT:
788 return "DDERR_SURFACEALREADYDEPENDENT";
789 case DDERR_SURFACEBUSY:
790 return "DDERR_SURFACEBUSY";
791 case DDERR_CANTLOCKSURFACE:
792 return "DDERR_CANTLOCKSURFACE";
793 case DDERR_SURFACEISOBSCURED:
794 return "DDERR_SURFACEISOBSCURED";
795 case DDERR_SURFACELOST:
796 return "DDERR_SURFACELOST";
797 case DDERR_SURFACENOTATTACHED:
798 return "DDERR_SURFACENOTATTACHED";
799 case DDERR_TOOBIGHEIGHT:
800 return "DDERR_TOOBIGHEIGHT";
801 case DDERR_TOOBIGSIZE:
802 return "DDERR_TOOBIGSIZE";
803 case DDERR_TOOBIGWIDTH:
804 return "DDERR_TOOBIGWIDTH";
805 case DDERR_UNSUPPORTED:
806 return "DDERR_UNSUPPORTED";
807 case DDERR_UNSUPPORTEDFORMAT:
808 return "DDERR_UNSUPPORTEDFORMAT";
809 case DDERR_UNSUPPORTEDMASK:
810 return "DDERR_UNSUPPORTEDMASK";
811 case DDERR_VERTICALBLANKINPROGRESS:
812 return "DDERR_VERTICALBLANKINPROGRESS";
813 case DDERR_WASSTILLDRAWING:
814 return "DDERR_WASSTILLDRAWING";
816 return "DDERR_XALIGN";
817 case DDERR_INVALIDDIRECTDRAWGUID:
818 return "DDERR_INVALIDDIRECTDRAWGUID";
819 case DDERR_DIRECTDRAWALREADYCREATED:
820 return "DDERR_DIRECTDRAWALREADYCREATED";
821 case DDERR_NODIRECTDRAWHW:
822 return "DDERR_NODIRECTDRAWHW";
823 case DDERR_PRIMARYSURFACEALREADYEXISTS:
824 return "DDERR_PRIMARYSURFACEALREADYEXISTS";
825 case DDERR_NOEMULATION:
826 return "DDERR_NOEMULATION";
827 case DDERR_REGIONTOOSMALL:
828 return "DDERR_REGIONTOOSMALL";
829 case DDERR_CLIPPERISUSINGHWND:
830 return "DDERR_CLIPPERISUSINGHWND";
831 case DDERR_NOCLIPPERATTACHED:
832 return "DDERR_NOCLIPPERATTACHED";
834 return "DDERR_NOHWND";
835 case DDERR_HWNDSUBCLASSED:
836 return "DDERR_HWNDSUBCLASSED";
837 case DDERR_HWNDALREADYSET:
838 return "DDERR_HWNDALREADYSET";
839 case DDERR_NOPALETTEATTACHED:
840 return "DDERR_NOPALETTEATTACHED";
841 case DDERR_NOPALETTEHW:
842 return "DDERR_NOPALETTEHW";
843 case DDERR_BLTFASTCANTCLIP:
844 return "DDERR_BLTFASTCANTCLIP";
846 return "DDERR_NOBLTHW";
847 case DDERR_NODDROPSHW:
848 return "DDERR_NODDROPSHW";
849 case DDERR_OVERLAYNOTVISIBLE:
850 return "DDERR_OVERLAYNOTVISIBLE";
851 case DDERR_NOOVERLAYDEST:
852 return "DDERR_NOOVERLAYDEST";
853 case DDERR_INVALIDPOSITION:
854 return "DDERR_INVALIDPOSITION";
855 case DDERR_NOTAOVERLAYSURFACE:
856 return "DDERR_NOTAOVERLAYSURFACE";
857 case DDERR_EXCLUSIVEMODEALREADYSET:
858 return "DDERR_EXCLUSIVEMODEALREADYSET";
859 case DDERR_NOTFLIPPABLE:
860 return "DDERR_NOTFLIPPABLE";
861 case DDERR_CANTDUPLICATE:
862 return "DDERR_CANTDUPLICATE";
863 case DDERR_NOTLOCKED:
864 return "DDERR_NOTLOCKED";
865 case DDERR_CANTCREATEDC:
866 return "DDERR_CANTCREATEDC";
869 case DDERR_WRONGMODE:
870 return "DDERR_WRONGMODE";
871 case DDERR_IMPLICITLYCREATED:
872 return "DDERR_IMPLICITLYCREATED";
873 case DDERR_NOTPALETTIZED:
874 return "DDERR_NOTPALETTIZED";
875 case DDERR_UNSUPPORTEDMODE:
876 return "DDERR_UNSUPPORTEDMODE";
877 case DDERR_NOMIPMAPHW:
878 return "DDERR_NOMIPMAPHW";
879 case DDERR_INVALIDSURFACETYPE:
880 return "DDERR_INVALIDSURFACETYPE";
881 case DDERR_DCALREADYCREATED:
882 return "DDERR_DCALREADYCREATED";
883 case DDERR_CANTPAGELOCK:
884 return "DDERR_CANTPAGELOCK";
885 case DDERR_CANTPAGEUNLOCK:
886 return "DDERR_CANTPAGEUNLOCK";
887 case DDERR_NOTPAGELOCKED:
888 return "DDERR_NOTPAGELOCKED";
889 case DDERR_NOTINITIALIZED:
890 return "DDERR_NOTINITIALIZED";
892 return "Unknown Error";
897 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
898 guint size, GstCaps * caps, GstBuffer ** buf)
900 GstDirectDrawSink *ddrawsink = NULL;
901 GstDDrawSurface *surface = NULL;
902 GstStructure *structure = NULL;
903 GstFlowReturn ret = GST_FLOW_OK;
905 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
906 GST_CAT_INFO (directdrawsink_debug, "a buffer of %d bytes was requested",
909 structure = gst_caps_get_structure (caps, 0);
911 g_mutex_lock (ddrawsink->pool_lock);
913 /* Inspect our buffer pool */
914 while (ddrawsink->buffer_pool) {
915 surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
918 /* Removing from the pool */
919 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
920 ddrawsink->buffer_pool);
922 /* If the surface is invalid for our need, destroy */
923 if ((surface->width != ddrawsink->video_width) ||
924 (surface->height != ddrawsink->video_height) ||
925 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
926 sizeof (DDPIXELFORMAT)))
928 gst_directdrawsink_surface_destroy (ddrawsink, surface);
931 /* We found a suitable surface */
937 /* We haven't found anything, creating a new one */
939 surface = gst_directdrawsink_surface_create (ddrawsink, caps, size);
942 /* Now we should have a surface, set appropriate caps on it */
944 gst_buffer_set_caps (GST_BUFFER (surface), caps);
947 g_mutex_unlock (ddrawsink->pool_lock);
949 *buf = GST_BUFFER (surface);
955 gst_directdrawsink_fill_colorkey (LPDIRECTDRAWSURFACE surface, DWORD dwColorKey)
962 ddbfx.dwSize = sizeof (DDBLTFX);
963 ddbfx.dwFillColor = dwColorKey;
965 if (IDirectDrawSurface_Blt (surface,
966 NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx) == DD_OK)
974 gst_directdrawsink_show_overlay (GstDirectDrawSink * ddrawsink)
977 RECT destsurf_rect, src_rect;
978 POINT dest_surf_point;
980 LPDIRECTDRAWSURFACE surface = NULL;
982 if (!ddrawsink || !ddrawsink->overlays)
985 if (ddrawsink->extern_surface)
986 surface = ddrawsink->extern_surface;
988 surface = ddrawsink->primary_surface;
990 if (ddrawsink->extern_surface) {
991 destsurf_rect.left = 0;
992 destsurf_rect.top = 0;
993 destsurf_rect.right = ddrawsink->out_width;
994 destsurf_rect.bottom = ddrawsink->out_height;
996 dest_surf_point.x = 0;
997 dest_surf_point.y = 0;
998 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
999 GetClientRect (ddrawsink->video_window, &destsurf_rect);
1000 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
1003 if (ddrawsink->keep_aspect_ratio) {
1006 src_rect.bottom = ddrawsink->video_height;
1007 src_rect.right = ddrawsink->video_width;
1008 gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
1011 gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
1013 ddofx.dwSize = sizeof (DDOVERLAYFX);
1014 ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
1015 ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
1017 hRes = IDirectDrawSurface_UpdateOverlay (ddrawsink->overlays,
1018 NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
1022 static GstFlowReturn
1023 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1025 GstDirectDrawSink *ddrawsink;
1028 DDSURFACEDESC surf_desc;
1029 RECT destsurf_rect, src_rect;
1030 POINT dest_surf_point;
1031 LPDIRECTDRAWSURFACE lpSurface = NULL;
1033 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1035 if (ddrawsink->extern_surface) {
1036 destsurf_rect.left = 0;
1037 destsurf_rect.top = 0;
1038 destsurf_rect.right = ddrawsink->out_width;
1039 destsurf_rect.bottom = ddrawsink->out_height;
1041 dest_surf_point.x = 0;
1042 dest_surf_point.y = 0;
1043 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
1044 GetClientRect (ddrawsink->video_window, &destsurf_rect);
1045 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
1048 if (ddrawsink->keep_aspect_ratio) {
1049 /*center image to dest image keeping aspect ratio */
1052 src_rect.bottom = ddrawsink->video_height;
1053 src_rect.right = ddrawsink->video_width;
1054 gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
1057 if (ddrawsink->bUseOverlay) {
1058 /*get the back buffer of the overlays flipping chain */
1061 ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
1062 IDirectDrawSurface_GetAttachedSurface (ddrawsink->overlays, &ddbackcaps,
1065 /*use our offscreen surface */
1066 lpSurface = ddrawsink->offscreen_surface;
1069 if (lpSurface == NULL)
1070 return GST_FLOW_ERROR;
1072 if (!GST_IS_DDRAWSURFACE (buf) ||
1073 ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
1076 guint src_pitch, line;
1078 /* Check for lost surface */
1079 if (IDirectDrawSurface_IsLost (lpSurface) == DDERR_SURFACELOST) {
1080 IDirectDrawSurface_Restore (lpSurface);
1083 ZeroMemory (&surf_desc, sizeof (surf_desc));
1084 surf_desc.dwSize = sizeof (surf_desc);
1086 /* Lock the surface */
1088 IDirectDrawSurface_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
1090 if (hRes != DD_OK) {
1091 GST_CAT_WARNING (directdrawsink_debug,
1092 "gst_directdrawsink_show_frame failed locking surface %s",
1093 DDErrorString (hRes));
1094 return GST_FLOW_ERROR;
1098 data = surf_desc.lpSurface;
1100 /* Source video rowbytes */
1101 src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
1103 /* Write each line respecting dest surface pitch */
1104 for (line = 0; line < surf_desc.dwHeight; line++) {
1105 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
1106 data += surf_desc.lPitch;
1109 /* Unlock the surface */
1110 hRes = IDirectDrawSurface_Unlock (lpSurface, NULL);
1111 if (hRes != DD_OK) {
1112 GST_CAT_WARNING (directdrawsink_debug,
1113 "gst_directdrawsink_show_frame failed unlocking surface %s",
1114 DDErrorString (hRes));
1115 return GST_FLOW_ERROR;
1118 if (ddrawsink->bUseOverlay) {
1119 /*Flip to front overlay */
1121 IDirectDrawSurface_Flip (ddrawsink->overlays, lpSurface, DDFLIP_WAIT);
1122 IDirectDrawSurface_Release (lpSurface);
1125 if (ddrawsink->extern_surface) {
1126 if (ddrawsink->out_height == ddrawsink->video_height &&
1127 ddrawsink->out_width == ddrawsink->video_width) {
1128 /*Fast blit to extern surface */
1129 hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
1130 lpSurface, NULL, DDBLTFAST_WAIT);
1133 /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1135 IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1136 lpSurface, NULL, DDBLT_WAIT, NULL);
1139 /*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
1141 IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1142 lpSurface, NULL, DDBLT_WAIT, NULL);
1147 GstDDrawSurface *surface = NULL;
1149 surface = GST_DDRAWSURFACE (buf);
1151 /* Unlocking surface before blit */
1152 IDirectDrawSurface_Unlock (surface->surface, NULL);
1153 surface->locked = FALSE;
1155 /* Check for lost surfaces */
1156 if (IDirectDrawSurface_IsLost (surface->surface) == DDERR_SURFACELOST) {
1157 IDirectDrawSurface_Restore (surface->surface);
1160 if (ddrawsink->bUseOverlay) {
1161 /* blit to the overlays back buffer */
1162 hRes = IDirectDrawSurface_Blt (lpSurface, NULL,
1163 surface->surface, NULL, DDBLT_WAIT, NULL);
1165 hRes = IDirectDrawSurface_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
1167 GST_CAT_WARNING (directdrawsink_debug, "error flipping");
1170 if (ddrawsink->extern_surface) {
1171 /*blit to the extern surface */
1172 if (ddrawsink->out_height == ddrawsink->video_height &&
1173 ddrawsink->out_width == ddrawsink->video_width) {
1174 /*Fast blit to extern surface */
1175 hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
1176 surface->surface, NULL, DDBLTFAST_WAIT);
1179 /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1181 IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1182 surface->surface, NULL, DDBLT_WAIT, NULL);
1185 /*blit to our primary surface */
1187 IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1188 surface->surface, NULL, DDBLT_WAIT, NULL);
1190 GST_CAT_WARNING (directdrawsink_debug,
1191 "IDirectDrawSurface_Blt returned %s", DDErrorString (hRes));
1193 GST_CAT_INFO (directdrawsink_debug,
1194 "allocated surface was blit to our primary");
1199 if (ddrawsink->bUseOverlay)
1200 gst_directdrawsink_show_overlay (ddrawsink);
1206 gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1208 gboolean bRet = TRUE;
1210 DWORD dwCooperativeLevel;
1211 DDSURFACEDESC dd_surface_desc;
1213 /*UUID IDirectDraw7_ID;
1215 //IDirectDraw_QueryInterface()
1216 create an instance of the ddraw object
1217 hRes = DirectDrawCreateEx (DDCREATE_EMULATIONONLY, (void**)&ddrawsink->ddraw_object,
1218 (REFIID)IID_IDirectDraw7, NULL);
1220 hRes = DirectDrawCreate (NULL, &ddrawsink->ddraw_object, NULL);
1221 if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
1222 GST_CAT_ERROR (directdrawsink_debug, "DirectDrawCreate failed with: %s",
1223 DDErrorString (hRes));
1227 /*get ddraw caps for the current hardware */
1228 /* ddrawsink->DDDriverCaps.dwSize = sizeof (DDCAPS);
1229 ddrawsink->DDHELCaps.dwSize = sizeof (DDCAPS);
1230 hRes = IDirectDraw_GetCaps (ddrawsink->ddraw_object, &ddrawsink->DDDriverCaps, &ddrawsink->DDHELCaps);
1232 /*set cooperative level */
1233 if (ddrawsink->fullscreen)
1234 dwCooperativeLevel = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
1236 dwCooperativeLevel = DDSCL_NORMAL;
1238 hRes = IDirectDraw_SetCooperativeLevel (ddrawsink->ddraw_object,
1239 ddrawsink->video_window, dwCooperativeLevel);
1240 if (hRes != DD_OK) {
1241 GST_CAT_ERROR (directdrawsink_debug, "SetCooperativeLevel failed with: %s",
1242 DDErrorString (hRes));
1246 /*for fullscreen mode, setup display mode */
1247 if (ddrawsink->fullscreen) {
1248 hRes = IDirectDraw_SetDisplayMode (ddrawsink->ddraw_object, 1440, 900, 32);
1251 if (!ddrawsink->extern_surface) {
1252 /*create our primary surface */
1253 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1254 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1255 dd_surface_desc.dwFlags = DDSD_CAPS;
1256 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1258 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1259 &ddrawsink->primary_surface, NULL);
1260 if (hRes != DD_OK) {
1261 GST_CAT_ERROR (directdrawsink_debug,
1262 "CreateSurface (primary) failed with: %s", DDErrorString (hRes));
1263 IDirectDraw_Release (ddrawsink->ddraw_object);
1267 hRes = IDirectDraw_CreateClipper (ddrawsink->ddraw_object, 0,
1268 &ddrawsink->clipper, NULL);
1269 if (hRes == DD_OK) {
1270 hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
1271 ddrawsink->video_window);
1272 hRes = IDirectDrawSurface_SetClipper (ddrawsink->primary_surface,
1273 ddrawsink->clipper);
1277 DDSURFACEDESC desc_surface;
1279 desc_surface.dwSize = sizeof (DDSURFACEDESC);
1281 /*get extern surface size */
1282 hRes = IDirectDrawSurface_GetSurfaceDesc (ddrawsink->extern_surface,
1284 if (hRes != DD_OK) {
1285 /*error while retrieving ext surface description */
1289 ddrawsink->out_width = desc_surface.dwWidth;
1290 ddrawsink->out_height = desc_surface.dwHeight;
1292 /*get extern surface pixel format (FIXME not needed if we are using overlays) */
1293 ddrawsink->dd_pixel_format.dwSize = sizeof (DDPIXELFORMAT);
1294 hRes = IDirectDrawSurface_GetPixelFormat (ddrawsink->extern_surface,
1295 &ddrawsink->dd_pixel_format);
1296 if (hRes != DD_OK) {
1297 /*error while retrieving ext surface pixel format */
1298 GST_CAT_WARNING (directdrawsink_debug,
1299 "GetPixelFormat (ddrawsink->extern_surface) failed with: %s",
1300 DDErrorString (hRes));
1304 /*get specific caps if needed ... */
1307 ddrawsink->setup = TRUE;
1313 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1316 /*case WM_ERASEBKGND:
1318 /* case WM_WINDOWPOSCHANGED:
1321 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1322 gst_directdrawsink_show_overlay(global_ddrawsink);
1325 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1327 if(global_ddrawsink->extern_surface)
1328 gst_directdrawsink_fill_colorkey(global_ddrawsink->extern_surface,
1329 global_ddrawsink->color_key);
1331 gst_directdrawsink_fill_colorkey(global_ddrawsink->primary_surface,
1332 global_ddrawsink->color_key);
1337 PostQuitMessage (0);
1340 DestroyWindow (hWnd);
1343 return DefWindowProc (hWnd, message, wParam, lParam);
1347 gst_directdrawsink_window_thread (GstDirectDrawSink * ddrawsink)
1351 memset (&WndClass, 0, sizeof (WNDCLASS));
1353 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1354 WndClass.hInstance = GetModuleHandle (NULL);
1355 WndClass.lpszClassName = "GStreamer-DirectDraw";
1356 WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
1357 WndClass.cbClsExtra = 0;
1358 WndClass.cbWndExtra = 0;
1359 WndClass.lpfnWndProc = WndProc;
1360 WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
1362 RegisterClass (&WndClass);
1364 ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
1365 "GStreamer-DirectDraw sink default window",
1366 WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
1367 WndClass.hInstance, NULL);
1369 if (ddrawsink->video_window == NULL)
1372 ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1374 /*start message loop processing our default window messages */
1378 if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
1380 DispatchMessage (&msg);
1387 gst_directdrawsink_create_default_window (GstDirectDrawSink * ddrawsink)
1389 ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1390 if (ddrawsink->window_created_signal == NULL)
1393 ddrawsink->window_thread = g_thread_create (
1394 (GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
1396 if (ddrawsink->window_thread == NULL)
1399 /* wait maximum 10 seconds for windows creating */
1400 if (WaitForSingleObject (ddrawsink->window_created_signal,
1401 10000) != WAIT_OBJECT_0)
1404 CloseHandle (ddrawsink->window_created_signal);
1408 CloseHandle (ddrawsink->window_created_signal);
1413 gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
1415 DDSURFACEDESC dd_surface_desc;
1418 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1419 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1421 dd_surface_desc.dwFlags =
1422 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1423 dd_surface_desc.dwHeight = ddrawsink->video_height;
1424 dd_surface_desc.dwWidth = ddrawsink->video_width;
1425 memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
1426 sizeof (DDPIXELFORMAT));
1428 if (ddrawsink->bUseOverlay) {
1429 /*create overlays flipping chain */
1430 dd_surface_desc.ddsCaps.dwCaps =
1431 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
1432 dd_surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
1433 dd_surface_desc.dwBackBufferCount = 1;
1435 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1436 &ddrawsink->overlays, NULL);
1438 if (hRes != DD_OK) {
1439 GST_CAT_WARNING (directdrawsink_debug,
1440 "create_ddraw_surfaces:CreateSurface(overlays) failed %s",
1441 DDErrorString (hRes));
1444 GST_CAT_INFO (directdrawsink_debug,
1445 "An overlay surfaces flipping chain was created");
1448 dd_surface_desc.ddsCaps.dwCaps =
1449 DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
1451 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1452 &ddrawsink->offscreen_surface, NULL);
1454 if (hRes != DD_OK) {
1455 GST_CAT_WARNING (directdrawsink_debug,
1456 "create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
1457 DDErrorString (hRes));
1466 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1467 GstClockTime * start, GstClockTime * end)
1469 GstDirectDrawSink *ddrawsink;
1471 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1473 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1474 *start = GST_BUFFER_TIMESTAMP (buf);
1475 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1476 *end = *start + GST_BUFFER_DURATION (buf);
1478 if (ddrawsink->fps_n > 0) {
1479 *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1486 gst_directdrawsink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1488 gint order = 0, binary;
1491 lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
1492 dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
1494 while (binary != 0) {
1495 if ((binary % 2) == 1)
1497 binary = binary >> 1;
1503 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1505 GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1506 GstCaps *format_caps = NULL;
1508 if (!ddrawsink || !lpDDSurfaceDesc)
1509 return DDENUMRET_CANCEL;
1511 if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
1512 GST_CAT_INFO (directdrawsink_debug,
1513 "Display mode found with DDSD_PIXELFORMAT not set");
1514 return DDENUMRET_OK;
1517 if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1518 return DDENUMRET_OK;
1520 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
1521 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1522 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1523 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
1524 "bpp", G_TYPE_INT, lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
1525 "depth", G_TYPE_INT,
1526 gst_directdrawsink_get_depth (&lpDDSurfaceDesc->ddpfPixelFormat),
1527 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "red_mask", G_TYPE_INT,
1528 lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask, "green_mask", G_TYPE_INT,
1529 lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask, "blue_mask", G_TYPE_INT,
1530 lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask, NULL);
1533 gst_caps_append (ddrawsink->caps, format_caps);
1536 return DDENUMRET_OK;
1540 gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1542 HRESULT hRes = S_OK;
1543 DWORD dwFourccCodeIndex = 0;
1544 LPDWORD pdwFourccCodes = NULL;
1545 DWORD dwNbFourccCodes = 0;
1546 GstCaps *format_caps = NULL;
1548 ddrawsink->caps = gst_caps_new_empty ();
1549 if (!ddrawsink->caps)
1552 /*enumerate display modes exposed by directdraw object */
1554 IDirectDraw_EnumDisplayModes (ddrawsink->ddraw_object, DDEDM_REFRESHRATES,
1555 NULL, ddrawsink, EnumModesCallback2);
1556 if (hRes != DD_OK) {
1557 GST_CAT_WARNING (directdrawsink_debug, "EnumDisplayModes returns: %s",
1558 DDErrorString (hRes));
1562 /* enumerate non-rgb modes exposed by directdraw object */
1563 IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object, &dwNbFourccCodes, NULL);
1564 if (dwNbFourccCodes != 0) {
1565 pdwFourccCodes = g_new0 (DWORD, dwNbFourccCodes);
1566 if (!pdwFourccCodes)
1569 if (FAILED (IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object,
1570 &dwNbFourccCodes, pdwFourccCodes))) {
1571 g_free (pdwFourccCodes);
1575 for (dwFourccCodeIndex = 0; dwFourccCodeIndex < dwNbFourccCodes;
1576 dwFourccCodeIndex++) {
1577 /*support only yuv formats YUY2, UYVY, YVU9, YV12, AYUV */
1578 if (pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'U', 'Y', '2')
1579 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('U', 'Y', 'V',
1581 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', 'U',
1583 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', '1',
1585 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('A', 'Y', 'U',
1588 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
1589 "format", GST_TYPE_FOURCC, pdwFourccCodes[dwFourccCodeIndex],
1590 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1591 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1592 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1595 gst_caps_append (ddrawsink->caps, format_caps);
1599 g_free (pdwFourccCodes);
1602 if (gst_caps_is_empty (ddrawsink->caps)) {
1603 gst_caps_unref (ddrawsink->caps);
1605 GST_ELEMENT_ERROR (ddrawsink, STREAM, WRONG_TYPE, (NULL),
1606 ("No supported format found"));
1610 return ddrawsink->caps;
1613 /* Creates miniobject and our internal surface */
1614 static GstDDrawSurface *
1615 gst_directdrawsink_surface_create (GstDirectDrawSink * ddrawsink,
1616 GstCaps * caps, size_t size)
1618 GstDDrawSurface *surface = NULL;
1619 GstStructure *structure = NULL;
1623 DDSURFACEDESC surf_desc, surf_lock_desc;
1625 g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1627 /*init structures */
1628 memset (&surf_desc, 0, sizeof (surf_desc));
1629 memset (&surf_lock_desc, 0, sizeof (surf_desc));
1630 surf_desc.dwSize = sizeof (surf_desc);
1631 surf_lock_desc.dwSize = sizeof (surf_lock_desc);
1633 /*create miniobject and initialize it */
1634 surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1635 surface->locked = FALSE;
1637 structure = gst_caps_get_structure (caps, 0);
1638 if (!gst_structure_get_int (structure, "width", &surface->width) ||
1639 !gst_structure_get_int (structure, "height", &surface->height)) {
1640 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
1643 pitch = GST_ROUND_UP_8 (size / surface->height);
1645 if (!gst_ddrawvideosink_get_format_from_caps (caps,
1646 &surface->dd_pixel_format)) {
1647 GST_WARNING ("failed getting pixel format from caps %" GST_PTR_FORMAT,
1651 if (ddrawsink->ddraw_object) {
1652 /* Creating an internal surface which will be used as GstBuffer, we used
1653 the detected pixel format and video dimensions */
1655 surf_desc.ddsCaps.dwCaps =
1656 DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1658 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1659 surf_desc.dwHeight = surface->height;
1660 surf_desc.dwWidth = surface->width;
1662 memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1663 sizeof (DDPIXELFORMAT));
1665 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1666 &surface->surface, NULL);
1667 if (hRes != DD_OK) {
1668 /*gst_object_unref (surface);
1671 goto surface_pitch_bad;
1674 /* Locking the surface to acquire the memory pointer.
1675 Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
1676 if directdraw api is used while a buffer is lock */
1677 hRes = IDirectDrawSurface_Lock (surface->surface, NULL, &surf_lock_desc,
1678 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1679 surface->locked = TRUE;
1681 if (surf_lock_desc.lPitch != pitch) {
1682 GST_CAT_INFO (directdrawsink_debug,
1683 "DDraw stride/pitch %ld isn't as expected value %d, let's continue allocating buffer.",
1684 surf_lock_desc.lPitch, pitch);
1686 /*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
1687 hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
1688 goto surface_pitch_bad;
1691 GST_CAT_INFO (directdrawsink_debug,
1692 "allocating a surface of %d bytes (stride=%ld)\n", size,
1693 surf_lock_desc.lPitch);
1694 GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
1695 GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
1699 GST_BUFFER (surface)->malloc_data = g_malloc (size);
1700 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
1701 GST_BUFFER_SIZE (surface) = size;
1703 /* surf_desc.dwSize = sizeof(DDSURFACEDESC);
1704 surf_desc.dwFlags = DDSD_PITCH | DDSD_LPSURFACE | DDSD_HEIGHT | DDSD_WIDTH ||DDSD_PIXELFORMAT;
1705 surf_desc.lpSurface = GST_BUFFER (surface)->malloc_data;
1706 surf_desc.lPitch = pitch;
1707 //surf_desc.dwHeight = surface->height;
1708 surf_desc.dwWidth = surface->width;
1709 hRes = IDirectDrawSurface7_SetSurfaceDesc(surface->surface, &surf_desc, 0);
1710 printf("%\n", DDErrorString(hRes));
1712 hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1713 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1715 surface->surface = NULL;
1716 /*printf ("allocating a buffer of %d bytes\n", size); */
1719 /* Keep a ref to our sink */
1720 surface->ddrawsink = gst_object_ref (ddrawsink);
1728 /* We are called from the finalize method of miniobject, the object will be
1729 * destroyed so we just have to clean our internal stuff */
1731 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
1732 GstDDrawSurface * surface)
1734 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
1736 /* Release our internal surface */
1737 if (surface->surface) {
1738 if (surface->locked) {
1739 IDirectDrawSurface_Unlock (surface->surface, NULL);
1740 surface->locked = FALSE;
1742 IDirectDrawSurface_Release (surface->surface);
1743 surface->surface = NULL;
1746 if (GST_BUFFER (surface)->malloc_data) {
1747 g_free (GST_BUFFER (surface)->malloc_data);
1748 GST_BUFFER (surface)->malloc_data = NULL;
1751 if (!surface->ddrawsink) {
1755 /* Release the ref to our sink */
1756 surface->ddrawsink = NULL;
1757 gst_object_unref (ddrawsink);
1762 GST_WARNING ("no sink found in surface");
1767 gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
1769 g_mutex_lock (ddrawsink->pool_lock);
1770 while (ddrawsink->buffer_pool) {
1771 GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
1773 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
1774 ddrawsink->buffer_pool);
1775 gst_directdrawsink_surface_destroy (ddrawsink, surface);
1777 g_mutex_unlock (ddrawsink->pool_lock);
1781 gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink)
1783 /* Post quit message and wait for our event window thread */
1784 if (ddrawsink->video_window)
1785 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
1786 if (ddrawsink->window_thread) {
1787 g_thread_join (ddrawsink->window_thread);
1788 ddrawsink->window_thread = NULL;
1791 if (ddrawsink->buffer_pool) {
1792 gst_directdrawsink_bufferpool_clear (ddrawsink);
1793 ddrawsink->buffer_pool = NULL;
1796 if (ddrawsink->display_modes) {
1797 GSList *walk = ddrawsink->display_modes;
1800 g_free (walk->data);
1801 walk = g_slist_next (walk);
1803 g_slist_free (ddrawsink->display_modes);
1804 ddrawsink->display_modes = NULL;
1807 if (ddrawsink->overlays) {
1808 IDirectDrawSurface_Release (ddrawsink->overlays);
1809 ddrawsink->overlays = NULL;
1812 if (ddrawsink->offscreen_surface) {
1813 IDirectDrawSurface_Release (ddrawsink->offscreen_surface);
1814 ddrawsink->offscreen_surface = NULL;
1817 if (ddrawsink->clipper) {
1818 IDirectDrawClipper_Release (ddrawsink->clipper);
1819 ddrawsink->clipper = NULL;
1822 if (ddrawsink->primary_surface) {
1823 IDirectDrawSurface_Release (ddrawsink->primary_surface);
1824 ddrawsink->primary_surface = NULL;
1827 if (ddrawsink->ddraw_object) {
1828 IDirectDraw_Release (ddrawsink->ddraw_object);
1829 ddrawsink->ddraw_object = NULL;
1832 ddrawsink->setup = FALSE;