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);
172 gst_ddrawvideosink_get_caps_from_format (DDPIXELFORMAT pixel_format)
174 GstCaps *caps = NULL;
178 if ((pixel_format.dwFlags & DDPF_RGB) == DDPF_RGB) {
179 bpp = pixel_format.dwRGBBitCount;
183 if ((pixel_format.dwFlags & DDPF_ALPHAPREMULT) == DDPF_ALPHAPREMULT)
188 caps = gst_caps_new_simple ("video/x-raw-rgb",
189 "bpp", G_TYPE_INT, bpp,
190 "depth", G_TYPE_INT, depth,
191 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
194 if ((pixel_format.dwFlags & DDPF_YUV) == DDPF_YUV) {
195 fourcc = pixel_format.dwFourCC;
196 caps = gst_caps_new_simple ("video/x-raw-yuv",
197 "format", GST_TYPE_FOURCC, fourcc, NULL);
200 g_assert (caps != NULL);
206 gst_directdrawsink_center_rect (RECT src, RECT dst, RECT * result)
208 gdouble src_ratio, dst_ratio;
209 long src_width = src.right;
210 long src_height = src.bottom;
211 long dst_width = dst.right - dst.left;
212 long dst_heigth = dst.bottom - dst.top;
213 long result_width = 0, result_height = 0;
215 g_return_if_fail (result != NULL);
217 src_ratio = (gdouble) src_width / src_height;
218 dst_ratio = (gdouble) dst_width / dst_heigth;
220 if (src_ratio > dst_ratio) {
222 result_height = (long) (dst_width / src_ratio);
224 result->left = dst.left;
225 result->right = dst.right;
226 result->top = dst.top + (dst_heigth - result_height) / 2;
227 result->bottom = result->top + result_height;
229 } else if (src_ratio < dst_ratio) {
231 result_width = (long) (dst_heigth * src_ratio);
233 result->top = dst.top;
234 result->bottom = dst.bottom;
235 result->left = dst.left + (dst_width - result_width) / 2;
236 result->right = result->left + result_width;
240 memcpy (result, &dst, sizeof (RECT));
243 GST_CAT_INFO (directdrawsink_debug,
244 "source is %dx%d dest is %dx%d, result is %dx%d with x,y %dx%d",
245 src_width, src_height, dst_width, dst_heigth,
246 result->right - result->left, result->bottom - result->top, result->left,
250 /*subclass of GstBuffer which manages surfaces lifetime*/
252 gst_ddrawsurface_finalize (GstDDrawSurface * surface)
254 GstDirectDrawSink *ddrawsink = NULL;
256 g_return_if_fail (surface != NULL);
258 ddrawsink = surface->ddrawsink;
262 /* If our geometry changed we can't reuse that image. */
263 if ((surface->width != ddrawsink->video_width) ||
264 (surface->height != ddrawsink->video_height) ||
265 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
266 sizeof (DDPIXELFORMAT)) != 0)
268 GST_CAT_INFO (directdrawsink_debug,
269 "destroy image as its size changed %dx%d vs current %dx%d",
270 surface->width, surface->height, ddrawsink->video_width,
271 ddrawsink->video_height);
272 gst_directdrawsink_surface_destroy (ddrawsink, surface);
275 /* In that case we can reuse the image and add it to our image pool. */
276 GST_CAT_INFO (directdrawsink_debug, "recycling image in pool");
278 /* need to increment the refcount again to recycle */
279 gst_buffer_ref (GST_BUFFER (surface));
281 g_mutex_lock (ddrawsink->pool_lock);
282 ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
283 g_mutex_unlock (ddrawsink->pool_lock);
288 GST_CAT_WARNING (directdrawsink_debug, "no sink found");
293 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
295 surface->surface = NULL;
298 surface->ddrawsink = NULL;
299 surface->locked = FALSE;
300 surface->system_memory = FALSE;
301 memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
305 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
307 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
309 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
310 gst_ddrawsurface_finalize;
314 gst_ddrawsurface_get_type (void)
316 static GType _gst_ddrawsurface_type;
318 if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
319 static const GTypeInfo ddrawsurface_info = {
320 sizeof (GstBufferClass),
323 gst_ddrawsurface_class_init,
326 sizeof (GstDDrawSurface),
328 (GInstanceInitFunc) gst_ddrawsurface_init,
331 _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
332 "GstDDrawSurface", &ddrawsurface_info, 0);
334 return _gst_ddrawsurface_type;
337 /* FIXME: this is problematic if there is more than one sink instance at the
338 * same time, surely there exists a better solution than this? */
339 /* static GstDirectDrawSink *global_ddrawsink = NULL; */
342 gst_directdrawsink_get_type (void)
344 static GType directdrawsink_type = 0;
346 if (!directdrawsink_type) {
347 static const GTypeInfo directdrawsink_info = {
348 sizeof (GstDirectDrawSinkClass),
349 gst_directdrawsink_base_init,
351 (GClassInitFunc) gst_directdrawsink_class_init,
354 sizeof (GstDirectDrawSink),
356 (GInstanceInitFunc) gst_directdrawsink_init,
359 directdrawsink_type =
360 g_type_register_static (GST_TYPE_VIDEO_SINK, "GstDirectDrawSink",
361 &directdrawsink_info, 0);
364 return directdrawsink_type;
368 gst_directdrawsink_base_init (gpointer g_class)
370 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
372 gst_element_class_set_details (element_class, &gst_directdrawsink_details);
374 gst_element_class_add_pad_template (element_class,
375 gst_static_pad_template_get (&directdrawsink_sink_factory));
379 gst_directdrawsink_class_init (GstDirectDrawSinkClass * klass)
381 GObjectClass *gobject_class;
382 GstElementClass *gstelement_class;
383 GstBaseSinkClass *gstbasesink_class;
385 gobject_class = (GObjectClass *) klass;
386 gstbasesink_class = (GstBaseSinkClass *) klass;
387 gstelement_class = (GstElementClass *) klass;
389 GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
392 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdrawsink_finalize);
394 gobject_class->get_property =
395 GST_DEBUG_FUNCPTR (gst_directdrawsink_get_property);
396 gobject_class->set_property =
397 GST_DEBUG_FUNCPTR (gst_directdrawsink_set_property);
399 gstelement_class->change_state =
400 GST_DEBUG_FUNCPTR (gst_directdrawsink_change_state);
401 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_get_caps);
402 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_set_caps);
403 gstbasesink_class->preroll =
404 GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
405 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
407 gstbasesink_class->get_times =
408 GST_DEBUG_FUNCPTR (gst_directdrawsink_get_times);
409 gstbasesink_class->buffer_alloc =
410 GST_DEBUG_FUNCPTR (gst_directdrawsink_buffer_alloc);
412 /*install properties */
413 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FULLSCREEN,
414 g_param_spec_boolean ("fullscreen", "fullscreen",
415 "boolean to activate fullscreen", FALSE, G_PARAM_READWRITE));
417 /*extern window where we will display the video */
418 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WINDOW,
419 g_param_spec_long ("window", "Window",
420 "The target window for video", G_MINLONG, G_MAXLONG, 0,
423 /*extern surface where we will blit the video */
424 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SURFACE,
425 g_param_spec_pointer ("surface", "Surface",
426 "The target surface for video", G_PARAM_WRITABLE));
428 /*setup aspect ratio mode */
429 g_object_class_install_property (G_OBJECT_CLASS (klass),
430 PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("keep-aspect-ratio",
431 "keep-aspect-ratio", "boolean to video keep aspect ratio", FALSE,
434 /*should add a color_key property to permit applications to define the color used for overlays */
438 gst_directdrawsink_set_property (GObject * object, guint prop_id,
439 const GValue * value, GParamSpec * pspec)
441 GstDirectDrawSink *ddrawsink;
443 ddrawsink = GST_DIRECTDRAW_SINK (object);
447 ddrawsink->extern_surface = g_value_get_pointer (value);
450 ddrawsink->video_window = (HWND) g_value_get_long (value);
451 ddrawsink->resize_window = FALSE;
453 case PROP_FULLSCREEN:
454 /*ddrawsink->fullscreen = g_value_get_boolean (value); not working .... */
456 case PROP_KEEP_ASPECT_RATIO:
457 ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
460 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
466 gst_directdrawsink_get_property (GObject * object, guint prop_id,
467 GValue * value, GParamSpec * pspec)
469 GstDirectDrawSink *ddrawsink;
471 ddrawsink = GST_DIRECTDRAW_SINK (object);
474 case PROP_FULLSCREEN:
475 g_value_set_boolean (value, ddrawsink->fullscreen);
477 case PROP_KEEP_ASPECT_RATIO:
478 g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
481 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487 gst_directdrawsink_finalize (GObject * object)
489 GstDirectDrawSink *ddrawsink;
491 ddrawsink = GST_DIRECTDRAW_SINK (object);
493 if (ddrawsink->pool_lock) {
494 g_mutex_free (ddrawsink->pool_lock);
495 ddrawsink->pool_lock = NULL;
497 if (ddrawsink->setup) {
498 gst_directdrawsink_cleanup (ddrawsink);
503 gst_directdrawsink_init (GstDirectDrawSink * ddrawsink,
504 GstDirectDrawSinkClass * g_class)
506 /*init members variables */
507 ddrawsink->ddraw_object = NULL;
508 ddrawsink->primary_surface = NULL;
509 ddrawsink->overlays = NULL;
510 ddrawsink->clipper = NULL;
511 ddrawsink->extern_surface = NULL;
513 /*video default values */
514 ddrawsink->video_height = 0;
515 ddrawsink->video_width = 0;
516 ddrawsink->fps_n = 0;
517 ddrawsink->fps_d = 0;
519 memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
521 ddrawsink->caps = NULL;
523 ddrawsink->window_thread = NULL;
525 ddrawsink->bUseOverlay = FALSE;
526 ddrawsink->color_key = 0; /*need to be a public property and may be we can enable overlays when this property is set ... */
528 ddrawsink->fullscreen = FALSE;
529 ddrawsink->setup = FALSE;
531 ddrawsink->display_modes = NULL;
532 ddrawsink->buffer_pool = NULL;
534 ddrawsink->resize_window = TRUE; /*resize only our internal window to the video size */
536 ddrawsink->pool_lock = g_mutex_new ();
538 ddrawsink->keep_aspect_ratio = TRUE;
539 /* ddrawsink->can_blit = TRUE;*/
543 gst_directdrawsink_get_caps (GstBaseSink * bsink)
545 GstDirectDrawSink *ddrawsink;
546 GstCaps *caps = NULL;
548 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
550 if (!ddrawsink->setup) {
551 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
554 GST_CAT_INFO (directdrawsink_debug,
555 "getcaps called and we are not setup yet, " "returning template %"
556 GST_PTR_FORMAT, caps);
558 /*if (ddrawsink->extern_surface) {
559 * We are not rendering to our own surface, returning this surface's
561 GST_WARNING ("using extern surface");
562 caps = gst_ddrawvideosink_get_caps_from_format (ddrawsink->dd_pixel_format);
565 /* i think we can't really use the format of the extern surface as the application owning the surface doesn't know
566 the format we will render. But we need to use overlays to overlay any format on the extern surface */
567 caps = gst_caps_ref (ddrawsink->caps);
574 gst_directdrawsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
576 GstDirectDrawSink *ddrawsink;
577 GstStructure *structure = NULL;
581 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
583 structure = gst_caps_get_structure (caps, 0);
587 ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
588 ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
590 fps = gst_structure_get_value (structure, "framerate");
591 ret &= (fps != NULL);
594 gst_ddrawvideosink_get_format_from_caps (caps,
595 &ddrawsink->dd_pixel_format);
600 ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
601 ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
603 if (ddrawsink->video_window && ddrawsink->resize_window) {
604 SetWindowPos (ddrawsink->video_window, NULL,
605 0, 0, ddrawsink->video_width + (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
606 ddrawsink->video_height + GetSystemMetrics (SM_CYCAPTION) +
607 (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
610 /*create overlays flipping chain */
611 ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
612 if (!ret && ddrawsink->bUseOverlay) {
613 GST_CAT_WARNING (directdrawsink_debug,
614 "Can not create overlay surface, reverting to no overlay display");
615 ddrawsink->bUseOverlay = FALSE;
616 ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
621 /*could not create draw surfaces even with fallback, so leave
623 ddrawsink->bUseOverlay = TRUE;
626 GST_CAT_ERROR (directdrawsink_debug, "Can not create ddraw surface");
631 static GstStateChangeReturn
632 gst_directdrawsink_change_state (GstElement * element,
633 GstStateChange transition)
635 GstDirectDrawSink *ddrawsink;
637 ddrawsink = GST_DIRECTDRAW_SINK (element);
639 switch (transition) {
640 case GST_STATE_CHANGE_NULL_TO_READY:
641 if (ddrawsink->video_window == NULL && ddrawsink->extern_surface == NULL)
642 if (!gst_directdrawsink_create_default_window (ddrawsink))
643 return GST_STATE_CHANGE_FAILURE;
645 if (!gst_directdrawsink_setup_ddraw (ddrawsink))
646 return GST_STATE_CHANGE_FAILURE;
648 if (!(ddrawsink->caps = gst_directdrawsink_get_ddrawcaps (ddrawsink)))
649 return GST_STATE_CHANGE_FAILURE;
652 case GST_STATE_CHANGE_READY_TO_PAUSED:
654 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
656 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
658 case GST_STATE_CHANGE_PAUSED_TO_READY:
660 ddrawsink->fps_n = 0;
661 ddrawsink->fps_d = 1;
662 ddrawsink->video_width = 0;
663 ddrawsink->video_height = 0;
665 if (ddrawsink->buffer_pool)
666 gst_directdrawsink_bufferpool_clear (ddrawsink);
669 case GST_STATE_CHANGE_READY_TO_NULL:
671 if (ddrawsink->setup)
672 gst_directdrawsink_cleanup (ddrawsink);
677 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
681 * Get DirectDraw error message.
683 * Returns: Text representation of the error.
686 DDErrorString (HRESULT hr)
689 case DDERR_ALREADYINITIALIZED:
690 return "DDERR_ALREADYINITIALIZED";
691 case DDERR_CANNOTATTACHSURFACE:
692 return "DDERR_CANNOTATTACHSURFACE";
693 case DDERR_CANNOTDETACHSURFACE:
694 return "DDERR_CANNOTDETACHSURFACE";
695 case DDERR_CURRENTLYNOTAVAIL:
696 return "DDERR_CURRENTLYNOTAVAIL";
697 case DDERR_EXCEPTION:
698 return "DDERR_EXCEPTION";
700 return "DDERR_GENERIC";
701 case DDERR_HEIGHTALIGN:
702 return "DDERR_HEIGHTALIGN";
703 case DDERR_INCOMPATIBLEPRIMARY:
704 return "DDERR_INCOMPATIBLEPRIMARY";
705 case DDERR_INVALIDCAPS:
706 return "DDERR_INVALIDCAPS";
707 case DDERR_INVALIDCLIPLIST:
708 return "DDERR_INVALIDCLIPLIST";
709 case DDERR_INVALIDMODE:
710 return "DDERR_INVALIDMODE";
711 case DDERR_INVALIDOBJECT:
712 return "DDERR_INVALIDOBJECT";
713 case DDERR_INVALIDPARAMS:
714 return "DDERR_INVALIDPARAMS";
715 case DDERR_INVALIDPIXELFORMAT:
716 return "DDERR_INVALIDPIXELFORMAT";
717 case DDERR_INVALIDRECT:
718 return "DDERR_INVALIDRECT";
719 case DDERR_LOCKEDSURFACES:
720 return "DDERR_LOCKEDSURFACES";
723 case DDERR_NOALPHAHW:
724 return "DDERR_NOALPHAHW";
725 case DDERR_NOCLIPLIST:
726 return "DDERR_NOCLIPLIST";
727 case DDERR_NOCOLORCONVHW:
728 return "DDERR_NOCOLORCONVHW";
729 case DDERR_NOCOOPERATIVELEVELSET:
730 return "DDERR_NOCOOPERATIVELEVELSET";
731 case DDERR_NOCOLORKEY:
732 return "DDERR_NOCOLORKEY";
733 case DDERR_NOCOLORKEYHW:
734 return "DDERR_NOCOLORKEYHW";
735 case DDERR_NODIRECTDRAWSUPPORT:
736 return "DDERR_NODIRECTDRAWSUPPORT";
737 case DDERR_NOEXCLUSIVEMODE:
738 return "DDERR_NOEXCLUSIVEMODE";
740 return "DDERR_NOFLIPHW";
742 return "DDERR_NOGDI";
743 case DDERR_NOMIRRORHW:
744 return "DDERR_NOMIRRORHW";
746 return "DDERR_NOTFOUND";
747 case DDERR_NOOVERLAYHW:
748 return "DDERR_NOOVERLAYHW";
749 case DDERR_NORASTEROPHW:
750 return "DDERR_NORASTEROPHW";
751 case DDERR_NOROTATIONHW:
752 return "DDERR_NOROTATIONHW";
753 case DDERR_NOSTRETCHHW:
754 return "DDERR_NOSTRETCHHW";
755 case DDERR_NOT4BITCOLOR:
756 return "DDERR_NOT4BITCOLOR";
757 case DDERR_NOT4BITCOLORINDEX:
758 return "DDERR_NOT4BITCOLORINDEX";
759 case DDERR_NOT8BITCOLOR:
760 return "DDERR_NOT8BITCOLOR";
761 case DDERR_NOTEXTUREHW:
762 return "DDERR_NOTEXTUREHW";
763 case DDERR_NOVSYNCHW:
764 return "DDERR_NOVSYNCHW";
765 case DDERR_NOZBUFFERHW:
766 return "DDERR_NOZBUFFERHW";
767 case DDERR_NOZOVERLAYHW:
768 return "DDERR_NOZOVERLAYHW";
769 case DDERR_OUTOFCAPS:
770 return "DDERR_OUTOFCAPS";
771 case DDERR_OUTOFMEMORY:
772 return "DDERR_OUTOFMEMORY";
773 case DDERR_OUTOFVIDEOMEMORY:
774 return "DDERR_OUTOFVIDEOMEMORY";
775 case DDERR_OVERLAYCANTCLIP:
776 return "DDERR_OVERLAYCANTCLIP";
777 case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
778 return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
779 case DDERR_PALETTEBUSY:
780 return "DDERR_PALETTEBUSY";
781 case DDERR_COLORKEYNOTSET:
782 return "DDERR_COLORKEYNOTSET";
783 case DDERR_SURFACEALREADYATTACHED:
784 return "DDERR_SURFACEALREADYATTACHED";
785 case DDERR_SURFACEALREADYDEPENDENT:
786 return "DDERR_SURFACEALREADYDEPENDENT";
787 case DDERR_SURFACEBUSY:
788 return "DDERR_SURFACEBUSY";
789 case DDERR_CANTLOCKSURFACE:
790 return "DDERR_CANTLOCKSURFACE";
791 case DDERR_SURFACEISOBSCURED:
792 return "DDERR_SURFACEISOBSCURED";
793 case DDERR_SURFACELOST:
794 return "DDERR_SURFACELOST";
795 case DDERR_SURFACENOTATTACHED:
796 return "DDERR_SURFACENOTATTACHED";
797 case DDERR_TOOBIGHEIGHT:
798 return "DDERR_TOOBIGHEIGHT";
799 case DDERR_TOOBIGSIZE:
800 return "DDERR_TOOBIGSIZE";
801 case DDERR_TOOBIGWIDTH:
802 return "DDERR_TOOBIGWIDTH";
803 case DDERR_UNSUPPORTED:
804 return "DDERR_UNSUPPORTED";
805 case DDERR_UNSUPPORTEDFORMAT:
806 return "DDERR_UNSUPPORTEDFORMAT";
807 case DDERR_UNSUPPORTEDMASK:
808 return "DDERR_UNSUPPORTEDMASK";
809 case DDERR_VERTICALBLANKINPROGRESS:
810 return "DDERR_VERTICALBLANKINPROGRESS";
811 case DDERR_WASSTILLDRAWING:
812 return "DDERR_WASSTILLDRAWING";
814 return "DDERR_XALIGN";
815 case DDERR_INVALIDDIRECTDRAWGUID:
816 return "DDERR_INVALIDDIRECTDRAWGUID";
817 case DDERR_DIRECTDRAWALREADYCREATED:
818 return "DDERR_DIRECTDRAWALREADYCREATED";
819 case DDERR_NODIRECTDRAWHW:
820 return "DDERR_NODIRECTDRAWHW";
821 case DDERR_PRIMARYSURFACEALREADYEXISTS:
822 return "DDERR_PRIMARYSURFACEALREADYEXISTS";
823 case DDERR_NOEMULATION:
824 return "DDERR_NOEMULATION";
825 case DDERR_REGIONTOOSMALL:
826 return "DDERR_REGIONTOOSMALL";
827 case DDERR_CLIPPERISUSINGHWND:
828 return "DDERR_CLIPPERISUSINGHWND";
829 case DDERR_NOCLIPPERATTACHED:
830 return "DDERR_NOCLIPPERATTACHED";
832 return "DDERR_NOHWND";
833 case DDERR_HWNDSUBCLASSED:
834 return "DDERR_HWNDSUBCLASSED";
835 case DDERR_HWNDALREADYSET:
836 return "DDERR_HWNDALREADYSET";
837 case DDERR_NOPALETTEATTACHED:
838 return "DDERR_NOPALETTEATTACHED";
839 case DDERR_NOPALETTEHW:
840 return "DDERR_NOPALETTEHW";
841 case DDERR_BLTFASTCANTCLIP:
842 return "DDERR_BLTFASTCANTCLIP";
844 return "DDERR_NOBLTHW";
845 case DDERR_NODDROPSHW:
846 return "DDERR_NODDROPSHW";
847 case DDERR_OVERLAYNOTVISIBLE:
848 return "DDERR_OVERLAYNOTVISIBLE";
849 case DDERR_NOOVERLAYDEST:
850 return "DDERR_NOOVERLAYDEST";
851 case DDERR_INVALIDPOSITION:
852 return "DDERR_INVALIDPOSITION";
853 case DDERR_NOTAOVERLAYSURFACE:
854 return "DDERR_NOTAOVERLAYSURFACE";
855 case DDERR_EXCLUSIVEMODEALREADYSET:
856 return "DDERR_EXCLUSIVEMODEALREADYSET";
857 case DDERR_NOTFLIPPABLE:
858 return "DDERR_NOTFLIPPABLE";
859 case DDERR_CANTDUPLICATE:
860 return "DDERR_CANTDUPLICATE";
861 case DDERR_NOTLOCKED:
862 return "DDERR_NOTLOCKED";
863 case DDERR_CANTCREATEDC:
864 return "DDERR_CANTCREATEDC";
867 case DDERR_WRONGMODE:
868 return "DDERR_WRONGMODE";
869 case DDERR_IMPLICITLYCREATED:
870 return "DDERR_IMPLICITLYCREATED";
871 case DDERR_NOTPALETTIZED:
872 return "DDERR_NOTPALETTIZED";
873 case DDERR_UNSUPPORTEDMODE:
874 return "DDERR_UNSUPPORTEDMODE";
875 case DDERR_NOMIPMAPHW:
876 return "DDERR_NOMIPMAPHW";
877 case DDERR_INVALIDSURFACETYPE:
878 return "DDERR_INVALIDSURFACETYPE";
879 case DDERR_DCALREADYCREATED:
880 return "DDERR_DCALREADYCREATED";
881 case DDERR_CANTPAGELOCK:
882 return "DDERR_CANTPAGELOCK";
883 case DDERR_CANTPAGEUNLOCK:
884 return "DDERR_CANTPAGEUNLOCK";
885 case DDERR_NOTPAGELOCKED:
886 return "DDERR_NOTPAGELOCKED";
887 case DDERR_NOTINITIALIZED:
888 return "DDERR_NOTINITIALIZED";
890 return "Unknown Error";
895 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
896 guint size, GstCaps * caps, GstBuffer ** buf)
898 GstDirectDrawSink *ddrawsink = NULL;
899 GstDDrawSurface *surface = NULL;
900 GstStructure *structure = NULL;
901 GstFlowReturn ret = GST_FLOW_OK;
903 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
904 GST_CAT_INFO (directdrawsink_debug, "a buffer of %d bytes was requested",
907 structure = gst_caps_get_structure (caps, 0);
909 g_mutex_lock (ddrawsink->pool_lock);
911 /* Inspect our buffer pool */
912 while (ddrawsink->buffer_pool) {
913 surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
916 /* Removing from the pool */
917 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
918 ddrawsink->buffer_pool);
920 /* If the surface is invalid for our need, destroy */
921 if ((surface->width != ddrawsink->video_width) ||
922 (surface->height != ddrawsink->video_height) ||
923 (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
924 sizeof (DDPIXELFORMAT)))
926 gst_directdrawsink_surface_destroy (ddrawsink, surface);
929 /* We found a suitable surface */
935 /* We haven't found anything, creating a new one */
937 surface = gst_directdrawsink_surface_create (ddrawsink, caps, size);
940 /* Now we should have a surface, set appropriate caps on it */
942 gst_buffer_set_caps (GST_BUFFER (surface), caps);
945 g_mutex_unlock (ddrawsink->pool_lock);
947 *buf = GST_BUFFER (surface);
953 gst_directdrawsink_fill_colorkey (LPDIRECTDRAWSURFACE surface, DWORD dwColorKey)
960 ddbfx.dwSize = sizeof (DDBLTFX);
961 ddbfx.dwFillColor = dwColorKey;
963 if (IDirectDrawSurface_Blt (surface,
964 NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx) == DD_OK)
972 gst_directdrawsink_show_overlay (GstDirectDrawSink * ddrawsink)
975 RECT destsurf_rect, src_rect;
976 POINT dest_surf_point;
978 LPDIRECTDRAWSURFACE surface = NULL;
980 if (!ddrawsink || !ddrawsink->overlays)
983 if (ddrawsink->extern_surface)
984 surface = ddrawsink->extern_surface;
986 surface = ddrawsink->primary_surface;
988 if (ddrawsink->extern_surface) {
989 destsurf_rect.left = 0;
990 destsurf_rect.top = 0;
991 destsurf_rect.right = ddrawsink->out_width;
992 destsurf_rect.bottom = ddrawsink->out_height;
994 dest_surf_point.x = 0;
995 dest_surf_point.y = 0;
996 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
997 GetClientRect (ddrawsink->video_window, &destsurf_rect);
998 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
1001 if (ddrawsink->keep_aspect_ratio) {
1004 src_rect.bottom = ddrawsink->video_height;
1005 src_rect.right = ddrawsink->video_width;
1006 gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
1009 gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
1011 ddofx.dwSize = sizeof (DDOVERLAYFX);
1012 ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
1013 ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
1015 hRes = IDirectDrawSurface_UpdateOverlay (ddrawsink->overlays,
1016 NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
1020 static GstFlowReturn
1021 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1023 GstDirectDrawSink *ddrawsink;
1026 DDSURFACEDESC surf_desc;
1027 RECT destsurf_rect, src_rect;
1028 POINT dest_surf_point;
1029 LPDIRECTDRAWSURFACE lpSurface = NULL;
1031 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1033 if (ddrawsink->extern_surface) {
1034 destsurf_rect.left = 0;
1035 destsurf_rect.top = 0;
1036 destsurf_rect.right = ddrawsink->out_width;
1037 destsurf_rect.bottom = ddrawsink->out_height;
1039 dest_surf_point.x = 0;
1040 dest_surf_point.y = 0;
1041 ClientToScreen (ddrawsink->video_window, &dest_surf_point);
1042 GetClientRect (ddrawsink->video_window, &destsurf_rect);
1043 OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
1046 if (ddrawsink->keep_aspect_ratio) {
1047 /*center image to dest image keeping aspect ratio */
1050 src_rect.bottom = ddrawsink->video_height;
1051 src_rect.right = ddrawsink->video_width;
1052 gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
1055 if (ddrawsink->bUseOverlay) {
1056 /*get the back buffer of the overlays flipping chain */
1059 ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
1060 IDirectDrawSurface_GetAttachedSurface (ddrawsink->overlays, &ddbackcaps,
1063 /*use our offscreen surface */
1064 lpSurface = ddrawsink->offscreen_surface;
1067 if (lpSurface == NULL)
1068 return GST_FLOW_ERROR;
1070 if (!GST_IS_DDRAWSURFACE (buf) ||
1071 ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
1074 guint src_pitch, line;
1076 /* Check for lost surface */
1077 if (IDirectDrawSurface_IsLost (lpSurface) == DDERR_SURFACELOST) {
1078 IDirectDrawSurface_Restore (lpSurface);
1081 ZeroMemory (&surf_desc, sizeof (surf_desc));
1082 surf_desc.dwSize = sizeof (surf_desc);
1084 /* Lock the surface */
1086 IDirectDrawSurface_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
1088 if (hRes != DD_OK) {
1089 GST_CAT_WARNING (directdrawsink_debug,
1090 "gst_directdrawsink_show_frame failed locking surface %s",
1091 DDErrorString (hRes));
1092 return GST_FLOW_ERROR;
1096 data = surf_desc.lpSurface;
1098 /* Source video rowbytes */
1099 src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
1101 /* Write each line respecting dest surface pitch */
1102 for (line = 0; line < surf_desc.dwHeight; line++) {
1103 memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
1104 data += surf_desc.lPitch;
1107 /* Unlock the surface */
1108 hRes = IDirectDrawSurface_Unlock (lpSurface, NULL);
1109 if (hRes != DD_OK) {
1110 GST_CAT_WARNING (directdrawsink_debug,
1111 "gst_directdrawsink_show_frame failed unlocking surface %s",
1112 DDErrorString (hRes));
1113 return GST_FLOW_ERROR;
1116 if (ddrawsink->bUseOverlay) {
1117 /*Flip to front overlay */
1119 IDirectDrawSurface_Flip (ddrawsink->overlays, lpSurface, DDFLIP_WAIT);
1120 IDirectDrawSurface_Release (lpSurface);
1123 if (ddrawsink->extern_surface) {
1124 if (ddrawsink->out_height == ddrawsink->video_height &&
1125 ddrawsink->out_width == ddrawsink->video_width) {
1126 /*Fast blit to extern surface */
1127 hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
1128 lpSurface, NULL, DDBLTFAST_WAIT);
1131 /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1133 IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1134 lpSurface, NULL, DDBLT_WAIT, NULL);
1137 /*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
1139 IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1140 lpSurface, NULL, DDBLT_WAIT, NULL);
1145 GstDDrawSurface *surface = NULL;
1147 surface = GST_DDRAWSURFACE (buf);
1149 /* Unlocking surface before blit */
1150 IDirectDrawSurface_Unlock (surface->surface, NULL);
1151 surface->locked = FALSE;
1153 /* Check for lost surfaces */
1154 if (IDirectDrawSurface_IsLost (surface->surface) == DDERR_SURFACELOST) {
1155 IDirectDrawSurface_Restore (surface->surface);
1158 if (ddrawsink->bUseOverlay) {
1159 /* blit to the overlays back buffer */
1160 hRes = IDirectDrawSurface_Blt (lpSurface, NULL,
1161 surface->surface, NULL, DDBLT_WAIT, NULL);
1163 hRes = IDirectDrawSurface_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
1165 GST_CAT_WARNING (directdrawsink_debug, "error flipping");
1168 if (ddrawsink->extern_surface) {
1169 /*blit to the extern surface */
1170 if (ddrawsink->out_height == ddrawsink->video_height &&
1171 ddrawsink->out_width == ddrawsink->video_width) {
1172 /*Fast blit to extern surface */
1173 hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
1174 surface->surface, NULL, DDBLTFAST_WAIT);
1177 /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1179 IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1180 surface->surface, NULL, DDBLT_WAIT, NULL);
1183 /*blit to our primary surface */
1185 IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1186 surface->surface, NULL, DDBLT_WAIT, NULL);
1188 GST_CAT_WARNING (directdrawsink_debug,
1189 "IDirectDrawSurface_Blt returned %s", DDErrorString (hRes));
1191 GST_CAT_INFO (directdrawsink_debug,
1192 "allocated surface was blit to our primary",
1193 DDErrorString (hRes));
1198 if (ddrawsink->bUseOverlay)
1199 gst_directdrawsink_show_overlay (ddrawsink);
1205 gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1207 gboolean bRet = TRUE;
1209 DWORD dwCooperativeLevel;
1210 DDSURFACEDESC dd_surface_desc;
1212 /*UUID IDirectDraw7_ID;
1214 //IDirectDraw_QueryInterface()
1215 /*create an instance of the ddraw object
1216 hRes = DirectDrawCreateEx (DDCREATE_EMULATIONONLY, (void**)&ddrawsink->ddraw_object,
1217 (REFIID)IID_IDirectDraw7, NULL);
1219 hRes = DirectDrawCreate (NULL, &ddrawsink->ddraw_object, NULL);
1220 if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
1221 GST_CAT_ERROR (directdrawsink_debug, "DirectDrawCreate failed with: %s",
1222 DDErrorString (hRes));
1226 /*get ddraw caps for the current hardware */
1227 /* ddrawsink->DDDriverCaps.dwSize = sizeof (DDCAPS);
1228 ddrawsink->DDHELCaps.dwSize = sizeof (DDCAPS);
1229 hRes = IDirectDraw_GetCaps (ddrawsink->ddraw_object, &ddrawsink->DDDriverCaps, &ddrawsink->DDHELCaps);
1231 /*set cooperative level */
1232 if (ddrawsink->fullscreen)
1233 dwCooperativeLevel = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
1235 dwCooperativeLevel = DDSCL_NORMAL;
1237 hRes = IDirectDraw_SetCooperativeLevel (ddrawsink->ddraw_object,
1238 ddrawsink->video_window, dwCooperativeLevel);
1239 if (hRes != DD_OK) {
1240 GST_CAT_ERROR (directdrawsink_debug, "SetCooperativeLevel failed with: %s",
1241 DDErrorString (hRes));
1245 /*for fullscreen mode, setup display mode */
1246 if (ddrawsink->fullscreen) {
1247 hRes = IDirectDraw_SetDisplayMode (ddrawsink->ddraw_object, 1440, 900, 32);
1250 if (!ddrawsink->extern_surface) {
1251 /*create our primary surface */
1252 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1253 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1254 dd_surface_desc.dwFlags = DDSD_CAPS;
1255 dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1257 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1258 &ddrawsink->primary_surface, NULL);
1259 if (hRes != DD_OK) {
1260 GST_CAT_ERROR (directdrawsink_debug,
1261 "CreateSurface (primary) failed with: %s", DDErrorString (hRes));
1262 IDirectDraw_Release (ddrawsink->ddraw_object);
1266 hRes = IDirectDraw_CreateClipper (ddrawsink->ddraw_object, 0,
1267 &ddrawsink->clipper, NULL);
1268 if (hRes == DD_OK) {
1269 hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
1270 ddrawsink->video_window);
1271 hRes = IDirectDrawSurface_SetClipper (ddrawsink->primary_surface,
1272 ddrawsink->clipper);
1276 DDSURFACEDESC desc_surface;
1278 desc_surface.dwSize = sizeof (DDSURFACEDESC);
1280 /*get extern surface size */
1281 hRes = IDirectDrawSurface_GetSurfaceDesc (ddrawsink->extern_surface,
1283 if (hRes != DD_OK) {
1284 /*error while retrieving ext surface description */
1288 ddrawsink->out_width = desc_surface.dwWidth;
1289 ddrawsink->out_height = desc_surface.dwHeight;
1291 /*get extern surface pixel format (FIXME not needed if we are using overlays) */
1292 ddrawsink->dd_pixel_format.dwSize = sizeof (DDPIXELFORMAT);
1293 hRes = IDirectDrawSurface_GetPixelFormat (ddrawsink->extern_surface,
1294 &ddrawsink->dd_pixel_format);
1295 if (hRes != DD_OK) {
1296 /*error while retrieving ext surface pixel format */
1297 GST_CAT_WARNING (directdrawsink_debug,
1298 "GetPixelFormat (ddrawsink->extern_surface) failed with: %s",
1299 DDErrorString (hRes));
1303 /*get specific caps if needed ... */
1306 ddrawsink->setup = TRUE;
1312 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1315 /*case WM_ERASEBKGND:
1317 /* case WM_WINDOWPOSCHANGED:
1320 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1321 gst_directdrawsink_show_overlay(global_ddrawsink);
1324 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1326 if(global_ddrawsink->extern_surface)
1327 gst_directdrawsink_fill_colorkey(global_ddrawsink->extern_surface,
1328 global_ddrawsink->color_key);
1330 gst_directdrawsink_fill_colorkey(global_ddrawsink->primary_surface,
1331 global_ddrawsink->color_key);
1336 PostQuitMessage (0);
1339 DestroyWindow (hWnd);
1342 return DefWindowProc (hWnd, message, wParam, lParam);
1346 gst_directdrawsink_window_thread (GstDirectDrawSink * ddrawsink)
1350 memset (&WndClass, 0, sizeof (WNDCLASS));
1352 WndClass.style = CS_HREDRAW | CS_VREDRAW;
1353 WndClass.hInstance = GetModuleHandle (NULL);
1354 WndClass.lpszClassName = "GStreamer-DirectDraw";
1355 WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
1356 WndClass.cbClsExtra = 0;
1357 WndClass.cbWndExtra = 0;
1358 WndClass.lpfnWndProc = WndProc;
1359 WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
1361 RegisterClass (&WndClass);
1363 ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
1364 "GStreamer-DirectDraw sink default window",
1365 WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
1366 WndClass.hInstance, NULL);
1368 if (ddrawsink->video_window == NULL)
1371 ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1373 /*start message loop processing our default window messages */
1377 if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
1379 DispatchMessage (&msg);
1386 gst_directdrawsink_create_default_window (GstDirectDrawSink * ddrawsink)
1388 ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1389 if (ddrawsink->window_created_signal == NULL)
1392 ddrawsink->window_thread = g_thread_create (
1393 (GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
1395 if (ddrawsink->window_thread == NULL)
1398 /* wait maximum 10 seconds for windows creating */
1399 if (WaitForSingleObject (ddrawsink->window_created_signal,
1400 10000) != WAIT_OBJECT_0)
1403 CloseHandle (ddrawsink->window_created_signal);
1407 CloseHandle (ddrawsink->window_created_signal);
1412 gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
1414 DDSURFACEDESC dd_surface_desc;
1417 memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1418 dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1420 dd_surface_desc.dwFlags =
1421 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1422 dd_surface_desc.dwHeight = ddrawsink->video_height;
1423 dd_surface_desc.dwWidth = ddrawsink->video_width;
1424 memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
1425 sizeof (DDPIXELFORMAT));
1427 if (ddrawsink->bUseOverlay) {
1428 /*create overlays flipping chain */
1429 dd_surface_desc.ddsCaps.dwCaps =
1430 DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
1431 dd_surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
1432 dd_surface_desc.dwBackBufferCount = 1;
1434 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1435 &ddrawsink->overlays, NULL);
1437 if (hRes != DD_OK) {
1438 GST_CAT_WARNING (directdrawsink_debug,
1439 "create_ddraw_surfaces:CreateSurface(overlays) failed %s",
1440 DDErrorString (hRes));
1443 GST_CAT_INFO (directdrawsink_debug,
1444 "An overlay surfaces flipping chain was created");
1447 dd_surface_desc.ddsCaps.dwCaps =
1448 DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
1450 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1451 &ddrawsink->offscreen_surface, NULL);
1453 if (hRes != DD_OK) {
1454 GST_CAT_WARNING (directdrawsink_debug,
1455 "create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
1456 DDErrorString (hRes));
1465 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1466 GstClockTime * start, GstClockTime * end)
1468 GstDirectDrawSink *ddrawsink;
1470 ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1472 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1473 *start = GST_BUFFER_TIMESTAMP (buf);
1474 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1475 *end = *start + GST_BUFFER_DURATION (buf);
1477 if (ddrawsink->fps_n > 0) {
1478 *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1485 gst_directdrawsink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1487 gint order = 0, binary;
1490 lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
1491 dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
1493 while (binary != 0) {
1494 if ((binary % 2) == 1)
1496 binary = binary >> 1;
1502 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1504 GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1505 GstCaps *format_caps = NULL;
1507 if (!ddrawsink || !lpDDSurfaceDesc)
1508 return DDENUMRET_CANCEL;
1510 if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
1511 GST_CAT_INFO (directdrawsink_debug,
1512 "Display mode found with DDSD_PIXELFORMAT not set");
1513 return DDENUMRET_OK;
1516 if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1517 return DDENUMRET_OK;
1519 format_caps = gst_caps_new_simple ("video/x-raw-rgb",
1520 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1521 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1522 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
1523 "bpp", G_TYPE_INT, lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
1524 "depth", G_TYPE_INT,
1525 gst_directdrawsink_get_depth (&lpDDSurfaceDesc->ddpfPixelFormat),
1526 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "red_mask", G_TYPE_INT,
1527 lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask, "green_mask", G_TYPE_INT,
1528 lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask, "blue_mask", G_TYPE_INT,
1529 lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask, NULL);
1532 gst_caps_append (ddrawsink->caps, format_caps);
1535 return DDENUMRET_OK;
1539 gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1541 HRESULT hRes = S_OK;
1542 DWORD dwFourccCodeIndex = 0;
1543 LPDWORD pdwFourccCodes = NULL;
1544 DWORD dwNbFourccCodes = 0;
1545 GstCaps *format_caps = NULL;
1547 ddrawsink->caps = gst_caps_new_empty ();
1548 if (!ddrawsink->caps)
1551 /*enumerate display modes exposed by directdraw object */
1553 IDirectDraw_EnumDisplayModes (ddrawsink->ddraw_object, DDEDM_REFRESHRATES,
1554 NULL, ddrawsink, EnumModesCallback2);
1555 if (hRes != DD_OK) {
1556 GST_CAT_WARNING (directdrawsink_debug, "EnumDisplayModes returns: %s",
1557 DDErrorString (hRes));
1561 /* enumerate non-rgb modes exposed by directdraw object */
1562 IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object, &dwNbFourccCodes, NULL);
1563 if (dwNbFourccCodes != 0) {
1564 pdwFourccCodes = g_new0 (DWORD, dwNbFourccCodes);
1565 if (!pdwFourccCodes)
1568 if (FAILED (IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object,
1569 &dwNbFourccCodes, pdwFourccCodes))) {
1570 g_free (pdwFourccCodes);
1574 for (dwFourccCodeIndex = 0; dwFourccCodeIndex < dwNbFourccCodes;
1575 dwFourccCodeIndex++) {
1576 /*support only yuv formats YUY2, UYVY, YVU9, YV12, AYUV */
1577 if (pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'U', 'Y', '2')
1578 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('U', 'Y', 'V',
1580 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', 'U',
1582 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', '1',
1584 || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('A', 'Y', 'U',
1587 format_caps = gst_caps_new_simple ("video/x-raw-yuv",
1588 "format", GST_TYPE_FOURCC, pdwFourccCodes[dwFourccCodeIndex],
1589 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1590 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1591 "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
1594 gst_caps_append (ddrawsink->caps, format_caps);
1598 g_free (pdwFourccCodes);
1601 if (gst_caps_is_empty (ddrawsink->caps)) {
1602 gst_caps_unref (ddrawsink->caps);
1604 GST_ELEMENT_ERROR (ddrawsink, STREAM, WRONG_TYPE, (NULL),
1605 ("No supported format found"));
1609 return ddrawsink->caps;
1612 /* Creates miniobject and our internal surface */
1613 static GstDDrawSurface *
1614 gst_directdrawsink_surface_create (GstDirectDrawSink * ddrawsink,
1615 GstCaps * caps, size_t size)
1617 GstDDrawSurface *surface = NULL;
1618 GstStructure *structure = NULL;
1622 DDSURFACEDESC surf_desc, surf_lock_desc;
1624 g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1626 /*init structures */
1627 memset (&surf_desc, 0, sizeof (surf_desc));
1628 memset (&surf_lock_desc, 0, sizeof (surf_desc));
1629 surf_desc.dwSize = sizeof (surf_desc);
1630 surf_lock_desc.dwSize = sizeof (surf_lock_desc);
1632 /*create miniobject and initialize it */
1633 surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1634 surface->locked = FALSE;
1636 structure = gst_caps_get_structure (caps, 0);
1637 if (!gst_structure_get_int (structure, "width", &surface->width) ||
1638 !gst_structure_get_int (structure, "height", &surface->height)) {
1639 GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
1642 pitch = GST_ROUND_UP_8 (size / surface->height);
1644 if (!gst_ddrawvideosink_get_format_from_caps (caps,
1645 &surface->dd_pixel_format)) {
1646 GST_WARNING ("failed getting pixel format from caps %" GST_PTR_FORMAT,
1650 if (ddrawsink->ddraw_object) {
1651 /* Creating an internal surface which will be used as GstBuffer, we used
1652 the detected pixel format and video dimensions */
1654 surf_desc.ddsCaps.dwCaps =
1655 DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1657 DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1658 surf_desc.dwHeight = surface->height;
1659 surf_desc.dwWidth = surface->width;
1661 memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1662 sizeof (DDPIXELFORMAT));
1664 hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1665 &surface->surface, NULL);
1666 if (hRes != DD_OK) {
1667 /*gst_object_unref (surface);
1670 goto surface_pitch_bad;
1673 /* Locking the surface to acquire the memory pointer.
1674 Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
1675 if directdraw api is used while a buffer is lock */
1676 hRes = IDirectDrawSurface_Lock (surface->surface, NULL, &surf_lock_desc,
1677 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1678 surface->locked = TRUE;
1680 if (surf_lock_desc.lPitch != pitch) {
1681 GST_CAT_INFO (directdrawsink_debug,
1682 "DDraw stride/pitch %d isn't as expected value %d, let's continue allocating buffer.",
1683 surf_lock_desc.lPitch, pitch);
1685 /*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
1686 hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
1687 goto surface_pitch_bad;
1690 GST_CAT_INFO (directdrawsink_debug,
1691 "allocating a surface of %d bytes (stride=%d)\n", size,
1692 surf_lock_desc.lPitch);
1693 GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
1694 GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
1698 GST_BUFFER (surface)->malloc_data = g_malloc (size);
1699 GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
1700 GST_BUFFER_SIZE (surface) = size;
1702 /* surf_desc.dwSize = sizeof(DDSURFACEDESC);
1703 surf_desc.dwFlags = DDSD_PITCH | DDSD_LPSURFACE | DDSD_HEIGHT | DDSD_WIDTH ||DDSD_PIXELFORMAT;
1704 surf_desc.lpSurface = GST_BUFFER (surface)->malloc_data;
1705 surf_desc.lPitch = pitch;
1706 //surf_desc.dwHeight = surface->height;
1707 surf_desc.dwWidth = surface->width;
1708 hRes = IDirectDrawSurface7_SetSurfaceDesc(surface->surface, &surf_desc, 0);
1709 printf("%\n", DDErrorString(hRes));
1711 hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1712 DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1714 surface->surface = NULL;
1715 /*printf ("allocating a buffer of %d bytes\n", size); */
1718 /* Keep a ref to our sink */
1719 surface->ddrawsink = gst_object_ref (ddrawsink);
1725 /* We are called from the finalize method of miniobject, the object will be
1726 * destroyed so we just have to clean our internal stuff */
1728 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
1729 GstDDrawSurface * surface)
1731 g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
1733 /* Release our internal surface */
1734 if (surface->surface) {
1735 if (surface->locked) {
1736 IDirectDrawSurface_Unlock (surface->surface, NULL);
1737 surface->locked = FALSE;
1739 IDirectDrawSurface_Release (surface->surface);
1740 surface->surface = NULL;
1743 if (GST_BUFFER (surface)->malloc_data) {
1744 g_free (GST_BUFFER (surface)->malloc_data);
1745 GST_BUFFER (surface)->malloc_data = NULL;
1748 if (!surface->ddrawsink) {
1752 /* Release the ref to our sink */
1753 surface->ddrawsink = NULL;
1754 gst_object_unref (ddrawsink);
1759 GST_WARNING ("no sink found in surface");
1764 gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
1766 g_mutex_lock (ddrawsink->pool_lock);
1767 while (ddrawsink->buffer_pool) {
1768 GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
1770 ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
1771 ddrawsink->buffer_pool);
1772 gst_directdrawsink_surface_destroy (ddrawsink, surface);
1774 g_mutex_unlock (ddrawsink->pool_lock);
1778 gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink)
1780 /* Post quit message and wait for our event window thread */
1781 if (ddrawsink->video_window)
1782 PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
1783 if (ddrawsink->window_thread) {
1784 g_thread_join (ddrawsink->window_thread);
1785 ddrawsink->window_thread = NULL;
1788 if (ddrawsink->buffer_pool) {
1789 gst_directdrawsink_bufferpool_clear (ddrawsink);
1790 ddrawsink->buffer_pool = NULL;
1793 if (ddrawsink->display_modes) {
1794 GSList *walk = ddrawsink->display_modes;
1797 g_free (walk->data);
1798 walk = g_slist_next (walk);
1800 g_slist_free (ddrawsink->display_modes);
1801 ddrawsink->display_modes = NULL;
1804 if (ddrawsink->overlays) {
1805 IDirectDrawSurface_Release (ddrawsink->overlays);
1806 ddrawsink->overlays = NULL;
1809 if (ddrawsink->offscreen_surface) {
1810 IDirectDrawSurface_Release (ddrawsink->offscreen_surface);
1811 ddrawsink->offscreen_surface = NULL;
1814 if (ddrawsink->clipper) {
1815 IDirectDrawClipper_Release (ddrawsink->clipper);
1816 ddrawsink->clipper = NULL;
1819 if (ddrawsink->primary_surface) {
1820 IDirectDrawSurface_Release (ddrawsink->primary_surface);
1821 ddrawsink->primary_surface = NULL;
1824 if (ddrawsink->ddraw_object) {
1825 IDirectDraw_Release (ddrawsink->ddraw_object);
1826 ddrawsink->ddraw_object = NULL;
1829 ddrawsink->setup = FALSE;