Add directdrawsink to build and dist it, so it gets built when compiling with MingW...
[platform/upstream/gst-plugins-good.git] / sys / directdraw / gstdirectdrawsink.c
1 /* GStreamer
2 * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
3 *       
4 * Based on directfb video sink
5 * gstdirectdrawsink.c:
6 *
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.
11 *
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.
16 *
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.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "gstdirectdrawsink.h"
28
29 #include <fcntl.h>
30 #include <errno.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <string.h>
35
36 GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
37 #define GST_CAT_DEFAULT directdrawsink_debug
38
39 /* elementfactory information */
40 static const GstElementDetails gst_directdrawsink_details =
41 GST_ELEMENT_DETAILS ("Video Sink (DIRECTDRAW)",
42     "Sink/Video",
43     "Output to a video card via DIRECTDRAW",
44     "Sebastien Moutte <sebastien@moutte.net>");
45
46 GST_BOILERPLATE (GstDirectDrawSink, gst_directdrawsink, GstVideoSink,
47     GST_TYPE_VIDEO_SINK);
48
49 static void gst_directdrawsink_finalize (GObject * object);
50
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);
55
56 static GstCaps *gst_directdrawsink_get_caps (GstBaseSink * bsink);
57 static gboolean gst_directdrawsink_set_caps (GstBaseSink * bsink,
58     GstCaps * caps);
59
60 static GstStateChangeReturn
61 gst_directdrawsink_change_state (GstElement * element,
62     GstStateChange transition);
63
64 static GstFlowReturn
65 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
66     guint size, GstCaps * caps, GstBuffer ** buf);
67
68 static void
69 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
70     GstClockTime * start, GstClockTime * end);
71
72 static GstFlowReturn
73 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf);
74
75 static gboolean gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink);
76 static gboolean gst_directdrawsink_create_default_window (GstDirectDrawSink *
77     ddrawsink);
78 static gboolean gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink *
79     ddrawsink);
80
81 static GstCaps *gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink *
82     ddrawsink);
83
84 static void gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink);
85 static void gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink);
86
87
88 /*surfaces management functions*/
89 static void
90 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
91     GstDDrawSurface * surface);
92
93 static GstDDrawSurface *gst_directdrawsink_surface_create (GstDirectDrawSink *
94     ddrawsink, GstCaps * caps, size_t size);
95
96 static GstStaticPadTemplate directdrawsink_sink_factory =
97     GST_STATIC_PAD_TEMPLATE ("sink",
98     GST_PAD_SINK,
99     GST_PAD_ALWAYS,
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 ]"
107         "; "
108         "video/x-raw-yuv, "
109         "framerate = (fraction) [ 0, MAX ], "
110         "width = (int) [ 1, MAX ], "
111         "height = (int) [ 1, MAX ], "
112         "format = (fourcc) { YUY2, UYVY, YVU9, YV12, AYUV }")
113     );
114
115 enum
116 {
117   PROP_0,
118   PROP_SURFACE,
119   PROP_WINDOW,
120   PROP_FULLSCREEN,
121   PROP_KEEP_ASPECT_RATIO
122 };
123
124 /* Utility functions */
125 static gboolean
126 gst_ddrawvideosink_get_format_from_caps (GstCaps * caps,
127     DDPIXELFORMAT * pPixelFormat)
128 {
129   GstStructure *structure = NULL;
130   gboolean ret = TRUE;
131
132   /*check params */
133   g_return_val_if_fail (pPixelFormat, FALSE);
134   g_return_val_if_fail (caps, FALSE);
135
136   /*init structure */
137   memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
138   pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
139
140   if (!(structure = gst_caps_get_structure (caps, 0)))
141     return FALSE;
142
143   if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
144     gint depth, bitcount, bitmask;
145
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")) {
157     gint fourcc;
158
159     pPixelFormat->dwFlags = DDPF_FOURCC;
160     ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
161     pPixelFormat->dwFourCC = fourcc;
162   } else {
163     GST_CAT_WARNING (directdrawsink_debug,
164         "unknown caps name received %" GST_PTR_FORMAT, caps);
165     ret = FALSE;
166   }
167
168   return ret;
169 }
170
171 /*
172 static GstCaps *
173 gst_ddrawvideosink_get_caps_from_format (DDPIXELFORMAT pixel_format)
174 {
175   GstCaps *caps = NULL;
176   gint bpp, depth;
177   guint32 fourcc;
178
179   if ((pixel_format.dwFlags & DDPF_RGB) == DDPF_RGB) {
180     bpp = pixel_format.dwRGBBitCount;
181     if (bpp != 32)
182       depth = bpp;
183     else {
184       if ((pixel_format.dwFlags & DDPF_ALPHAPREMULT) == DDPF_ALPHAPREMULT)
185         depth = 32;
186       else
187         depth = 24;
188     }
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);
193   }
194
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);
199   }
200
201   g_assert (caps != NULL);
202
203   return caps;
204 }
205 */
206
207 static void
208 gst_directdrawsink_center_rect (RECT src, RECT dst, RECT * result)
209 {
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;
216
217   g_return_if_fail (result != NULL);
218
219   src_ratio = (gdouble) src_width / src_height;
220   dst_ratio = (gdouble) dst_width / dst_heigth;
221
222   if (src_ratio > dst_ratio) {
223     /*new height */
224     result_height = (long) (dst_width / src_ratio);
225
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;
230
231   } else if (src_ratio < dst_ratio) {
232     /*new width */
233     result_width = (long) (dst_heigth * src_ratio);
234
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;
239
240   } else {
241     /*same ratio */
242     memcpy (result, &dst, sizeof (RECT));
243   }
244
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,
249       result->right);
250 }
251
252 /*subclass of GstBuffer which manages surfaces lifetime*/
253 static void
254 gst_ddrawsurface_finalize (GstDDrawSurface * surface)
255 {
256   GstDirectDrawSink *ddrawsink = NULL;
257
258   g_return_if_fail (surface != NULL);
259
260   ddrawsink = surface->ddrawsink;
261   if (!ddrawsink)
262     goto no_sink;
263
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)
269       ) {
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);
275
276   } else {
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");
279
280     /* need to increment the refcount again to recycle */
281     gst_buffer_ref (GST_BUFFER (surface));
282
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);
286   }
287   return;
288
289 no_sink:
290   GST_CAT_WARNING (directdrawsink_debug, "no sink found");
291   return;
292 }
293
294 static void
295 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
296 {
297   surface->surface = NULL;
298   surface->width = 0;
299   surface->height = 0;
300   surface->ddrawsink = NULL;
301   surface->locked = FALSE;
302   surface->system_memory = FALSE;
303   memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
304 }
305
306 static void
307 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
308 {
309   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
310
311   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
312       gst_ddrawsurface_finalize;
313 }
314
315 GType
316 gst_ddrawsurface_get_type (void)
317 {
318   static GType _gst_ddrawsurface_type;
319
320   if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
321     static const GTypeInfo ddrawsurface_info = {
322       sizeof (GstBufferClass),
323       NULL,
324       NULL,
325       gst_ddrawsurface_class_init,
326       NULL,
327       NULL,
328       sizeof (GstDDrawSurface),
329       0,
330       (GInstanceInitFunc) gst_ddrawsurface_init,
331       NULL
332     };
333     _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
334         "GstDDrawSurface", &ddrawsurface_info, 0);
335   }
336   return _gst_ddrawsurface_type;
337 }
338
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; */
342
343 /*GType
344 gst_directdrawsink_get_type (void)
345 {
346   static GType directdrawsink_type = 0;
347
348   if (!directdrawsink_type) {
349     static const GTypeInfo directdrawsink_info = {
350       sizeof (GstDirectDrawSinkClass),
351       gst_directdrawsink_base_init,
352       NULL,
353       (GClassInitFunc) gst_directdrawsink_class_init,
354       NULL,
355       NULL,
356       sizeof (GstDirectDrawSink),
357       0,
358       (GInstanceInitFunc) gst_directdrawsink_init,
359     };
360
361     directdrawsink_type =
362         g_type_register_static (GST_TYPE_VIDEO_SINK, "GstDirectDrawSink",
363         &directdrawsink_info, 0);
364   }
365
366   return directdrawsink_type;
367 }
368 */
369 static void
370 gst_directdrawsink_base_init (gpointer g_class)
371 {
372   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
373
374   gst_element_class_set_details (element_class, &gst_directdrawsink_details);
375
376   gst_element_class_add_pad_template (element_class,
377       gst_static_pad_template_get (&directdrawsink_sink_factory));
378 }
379
380 static void
381 gst_directdrawsink_class_init (GstDirectDrawSinkClass * klass)
382 {
383   GObjectClass *gobject_class;
384   GstElementClass *gstelement_class;
385   GstBaseSinkClass *gstbasesink_class;
386
387   gobject_class = (GObjectClass *) klass;
388   gstbasesink_class = (GstBaseSinkClass *) klass;
389   gstelement_class = (GstElementClass *) klass;
390
391   GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
392       "Direct draw sink");
393
394   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdrawsink_finalize);
395
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);
400
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);
408
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);
413
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));
418
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,
423           G_PARAM_WRITABLE));
424
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));
429
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,
434           G_PARAM_READWRITE));
435
436   /*should add a color_key property to permit applications to define the color used for overlays */
437 }
438
439 static void
440 gst_directdrawsink_set_property (GObject * object, guint prop_id,
441     const GValue * value, GParamSpec * pspec)
442 {
443   GstDirectDrawSink *ddrawsink;
444
445   ddrawsink = GST_DIRECTDRAW_SINK (object);
446
447   switch (prop_id) {
448     case PROP_SURFACE:
449       ddrawsink->extern_surface = g_value_get_pointer (value);
450       break;
451     case PROP_WINDOW:
452       ddrawsink->video_window = (HWND) g_value_get_long (value);
453       ddrawsink->resize_window = FALSE;
454       break;
455     case PROP_FULLSCREEN:
456       /*ddrawsink->fullscreen = g_value_get_boolean (value); not working .... */
457       break;
458     case PROP_KEEP_ASPECT_RATIO:
459       ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
460       break;
461     default:
462       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
463       break;
464   }
465 }
466
467 static void
468 gst_directdrawsink_get_property (GObject * object, guint prop_id,
469     GValue * value, GParamSpec * pspec)
470 {
471   GstDirectDrawSink *ddrawsink;
472
473   ddrawsink = GST_DIRECTDRAW_SINK (object);
474
475   switch (prop_id) {
476     case PROP_FULLSCREEN:
477       g_value_set_boolean (value, ddrawsink->fullscreen);
478       break;
479     case PROP_KEEP_ASPECT_RATIO:
480       g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
481       break;
482     default:
483       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
484       break;
485   }
486 }
487
488 static void
489 gst_directdrawsink_finalize (GObject * object)
490 {
491   GstDirectDrawSink *ddrawsink;
492
493   ddrawsink = GST_DIRECTDRAW_SINK (object);
494
495   if (ddrawsink->pool_lock) {
496     g_mutex_free (ddrawsink->pool_lock);
497     ddrawsink->pool_lock = NULL;
498   }
499   if (ddrawsink->setup) {
500     gst_directdrawsink_cleanup (ddrawsink);
501   }
502 }
503
504 static void
505 gst_directdrawsink_init (GstDirectDrawSink * ddrawsink,
506     GstDirectDrawSinkClass * g_class)
507 {
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;
514
515   /*video default values */
516   ddrawsink->video_height = 0;
517   ddrawsink->video_width = 0;
518   ddrawsink->fps_n = 0;
519   ddrawsink->fps_d = 0;
520
521   memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
522
523   ddrawsink->caps = NULL;
524
525   ddrawsink->window_thread = NULL;
526
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 ... */
529
530   ddrawsink->fullscreen = FALSE;
531   ddrawsink->setup = FALSE;
532
533   ddrawsink->display_modes = NULL;
534   ddrawsink->buffer_pool = NULL;
535
536   ddrawsink->resize_window = TRUE;      /*resize only our internal window to the video size */
537
538   ddrawsink->pool_lock = g_mutex_new ();
539
540   ddrawsink->keep_aspect_ratio = TRUE;
541 /*  ddrawsink->can_blit = TRUE;*/
542 }
543
544 static GstCaps *
545 gst_directdrawsink_get_caps (GstBaseSink * bsink)
546 {
547   GstDirectDrawSink *ddrawsink;
548   GstCaps *caps = NULL;
549
550   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
551
552   if (!ddrawsink->setup) {
553     caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
554             (ddrawsink)));
555
556     GST_CAT_INFO (directdrawsink_debug,
557         "getcaps called and we are not setup yet, " "returning template %"
558         GST_PTR_FORMAT, caps);
559   } else {
560     /*if (ddrawsink->extern_surface) {
561      * We are not rendering to our own surface, returning this surface's
562      *  pixel format *
563      GST_WARNING ("using extern surface");
564      caps = gst_ddrawvideosink_get_caps_from_format (ddrawsink->dd_pixel_format);
565      } else */
566
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);
570   }
571
572   return caps;
573 }
574
575 static gboolean
576 gst_directdrawsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
577 {
578   GstDirectDrawSink *ddrawsink;
579   GstStructure *structure = NULL;
580   gboolean ret;
581   const GValue *fps;
582
583   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
584
585   structure = gst_caps_get_structure (caps, 0);
586   if (!structure)
587     return FALSE;
588
589   ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
590   ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
591
592   fps = gst_structure_get_value (structure, "framerate");
593   ret &= (fps != NULL);
594
595   ret &=
596       gst_ddrawvideosink_get_format_from_caps (caps,
597       &ddrawsink->dd_pixel_format);
598
599   if (!ret)
600     return FALSE;
601
602   ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
603   ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
604
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);
610   }
611
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);
619     if (ret) {
620       return TRUE;
621     }
622
623     /*could not create draw surfaces even with fallback, so leave
624        everything as is */
625     ddrawsink->bUseOverlay = TRUE;
626   }
627   if (!ret) {
628     GST_CAT_ERROR (directdrawsink_debug, "Can not create ddraw surface");
629   }
630   return ret;
631 }
632
633 static GstStateChangeReturn
634 gst_directdrawsink_change_state (GstElement * element,
635     GstStateChange transition)
636 {
637   GstDirectDrawSink *ddrawsink;
638
639   ddrawsink = GST_DIRECTDRAW_SINK (element);
640
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;
646
647       if (!gst_directdrawsink_setup_ddraw (ddrawsink))
648         return GST_STATE_CHANGE_FAILURE;
649
650       if (!(ddrawsink->caps = gst_directdrawsink_get_ddrawcaps (ddrawsink)))
651         return GST_STATE_CHANGE_FAILURE;
652
653       break;
654     case GST_STATE_CHANGE_READY_TO_PAUSED:
655       break;
656     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
657       break;
658     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
659       break;
660     case GST_STATE_CHANGE_PAUSED_TO_READY:
661
662       ddrawsink->fps_n = 0;
663       ddrawsink->fps_d = 1;
664       ddrawsink->video_width = 0;
665       ddrawsink->video_height = 0;
666
667       if (ddrawsink->buffer_pool)
668         gst_directdrawsink_bufferpool_clear (ddrawsink);
669
670       break;
671     case GST_STATE_CHANGE_READY_TO_NULL:
672
673       if (ddrawsink->setup)
674         gst_directdrawsink_cleanup (ddrawsink);
675
676       break;
677   }
678
679   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
680 }
681
682 /**
683  * Get DirectDraw error message.
684  * @hr: HRESULT code
685  * Returns: Text representation of the error.
686  */
687 char *
688 DDErrorString (HRESULT hr)
689 {
690   switch (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";
701     case DDERR_GENERIC:
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";
723     case DDERR_NO3D:
724       return "DDERR_NO3D";
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";
741     case DDERR_NOFLIPHW:
742       return "DDERR_NOFLIPHW";
743     case DDERR_NOGDI:
744       return "DDERR_NOGDI";
745     case DDERR_NOMIRRORHW:
746       return "DDERR_NOMIRRORHW";
747     case DDERR_NOTFOUND:
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";
815     case DDERR_XALIGN:
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";
833     case DDERR_NOHWND:
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";
845     case DDERR_NOBLTHW:
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";
867     case DDERR_NODC:
868       return "DDERR_NODC";
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";
891   }
892   return "Unknown Error";
893 }
894
895
896 static GstFlowReturn
897 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
898     guint size, GstCaps * caps, GstBuffer ** buf)
899 {
900   GstDirectDrawSink *ddrawsink = NULL;
901   GstDDrawSurface *surface = NULL;
902   GstStructure *structure = NULL;
903   GstFlowReturn ret = GST_FLOW_OK;
904
905   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
906   GST_CAT_INFO (directdrawsink_debug, "a buffer of %d bytes was requested",
907       size);
908
909   structure = gst_caps_get_structure (caps, 0);
910
911   g_mutex_lock (ddrawsink->pool_lock);
912
913   /* Inspect our buffer pool */
914   while (ddrawsink->buffer_pool) {
915     surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
916
917     if (surface) {
918       /* Removing from the pool */
919       ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
920           ddrawsink->buffer_pool);
921
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)))
927           ) {
928         gst_directdrawsink_surface_destroy (ddrawsink, surface);
929         surface = NULL;
930       } else {
931         /* We found a suitable surface */
932         break;
933       }
934     }
935   }
936
937   /* We haven't found anything, creating a new one */
938   if (!surface) {
939     surface = gst_directdrawsink_surface_create (ddrawsink, caps, size);
940   }
941
942   /* Now we should have a surface, set appropriate caps on it */
943   if (surface) {
944     gst_buffer_set_caps (GST_BUFFER (surface), caps);
945   }
946
947   g_mutex_unlock (ddrawsink->pool_lock);
948
949   *buf = GST_BUFFER (surface);
950
951   return ret;
952 }
953
954 static gboolean
955 gst_directdrawsink_fill_colorkey (LPDIRECTDRAWSURFACE surface, DWORD dwColorKey)
956 {
957   DDBLTFX ddbfx;
958
959   if (!surface)
960     return FALSE;
961
962   ddbfx.dwSize = sizeof (DDBLTFX);
963   ddbfx.dwFillColor = dwColorKey;
964
965   if (IDirectDrawSurface_Blt (surface,
966           NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx) == DD_OK)
967     return TRUE;
968   else
969     return FALSE;
970 }
971
972
973 static void
974 gst_directdrawsink_show_overlay (GstDirectDrawSink * ddrawsink)
975 {
976   HRESULT hRes;
977   RECT destsurf_rect, src_rect;
978   POINT dest_surf_point;
979   DDOVERLAYFX ddofx;
980   LPDIRECTDRAWSURFACE surface = NULL;
981
982   if (!ddrawsink || !ddrawsink->overlays)
983     return;
984
985   if (ddrawsink->extern_surface)
986     surface = ddrawsink->extern_surface;
987   else
988     surface = ddrawsink->primary_surface;
989
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;
995   } else {
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);
1001   }
1002
1003   if (ddrawsink->keep_aspect_ratio) {
1004     src_rect.top = 0;
1005     src_rect.left = 0;
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);
1009   }
1010
1011   gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
1012
1013   ddofx.dwSize = sizeof (DDOVERLAYFX);
1014   ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
1015   ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
1016
1017   hRes = IDirectDrawSurface_UpdateOverlay (ddrawsink->overlays,
1018       NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
1019       &ddofx);
1020 }
1021
1022 static GstFlowReturn
1023 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1024 {
1025   GstDirectDrawSink *ddrawsink;
1026   HRESULT hRes;
1027
1028   DDSURFACEDESC surf_desc;
1029   RECT destsurf_rect, src_rect;
1030   POINT dest_surf_point;
1031   LPDIRECTDRAWSURFACE lpSurface = NULL;
1032
1033   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1034
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;
1040   } else {
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);
1046   }
1047
1048   if (ddrawsink->keep_aspect_ratio) {
1049     /*center image to dest image keeping aspect ratio */
1050     src_rect.top = 0;
1051     src_rect.left = 0;
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);
1055   }
1056
1057   if (ddrawsink->bUseOverlay) {
1058     /*get the back buffer of the overlays flipping chain */
1059     DDSCAPS ddbackcaps;
1060
1061     ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
1062     IDirectDrawSurface_GetAttachedSurface (ddrawsink->overlays, &ddbackcaps,
1063         &lpSurface);
1064   } else {
1065     /*use our offscreen surface */
1066     lpSurface = ddrawsink->offscreen_surface;
1067   }
1068
1069   if (lpSurface == NULL)
1070     return GST_FLOW_ERROR;
1071
1072   if (!GST_IS_DDRAWSURFACE (buf) ||
1073       ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
1074
1075     LPBYTE data = NULL;
1076     guint src_pitch, line;
1077
1078     /* Check for lost surface */
1079     if (IDirectDrawSurface_IsLost (lpSurface) == DDERR_SURFACELOST) {
1080       IDirectDrawSurface_Restore (lpSurface);
1081     }
1082
1083     ZeroMemory (&surf_desc, sizeof (surf_desc));
1084     surf_desc.dwSize = sizeof (surf_desc);
1085
1086     /* Lock the surface */
1087     hRes =
1088         IDirectDrawSurface_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
1089         NULL);
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;
1095     }
1096
1097     /* Write data */
1098     data = surf_desc.lpSurface;
1099
1100     /* Source video rowbytes */
1101     src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
1102
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;
1107     }
1108
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;
1116     }
1117
1118     if (ddrawsink->bUseOverlay) {
1119       /*Flip to front overlay */
1120       hRes =
1121           IDirectDrawSurface_Flip (ddrawsink->overlays, lpSurface, DDFLIP_WAIT);
1122       IDirectDrawSurface_Release (lpSurface);
1123       lpSurface = NULL;
1124     } else {
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);
1131
1132         } else {
1133           /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1134           hRes =
1135               IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1136               lpSurface, NULL, DDBLT_WAIT, NULL);
1137         }
1138       } else {
1139         /*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
1140         hRes =
1141             IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1142             lpSurface, NULL, DDBLT_WAIT, NULL);
1143       }
1144     }
1145   } else {
1146
1147     GstDDrawSurface *surface = NULL;
1148
1149     surface = GST_DDRAWSURFACE (buf);
1150
1151     /* Unlocking surface before blit */
1152     IDirectDrawSurface_Unlock (surface->surface, NULL);
1153     surface->locked = FALSE;
1154
1155     /* Check for lost surfaces */
1156     if (IDirectDrawSurface_IsLost (surface->surface) == DDERR_SURFACELOST) {
1157       IDirectDrawSurface_Restore (surface->surface);
1158     }
1159
1160     if (ddrawsink->bUseOverlay) {
1161       /* blit to the overlays back buffer */
1162       hRes = IDirectDrawSurface_Blt (lpSurface, NULL,
1163           surface->surface, NULL, DDBLT_WAIT, NULL);
1164
1165       hRes = IDirectDrawSurface_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
1166       if (hRes != DD_OK)
1167         GST_CAT_WARNING (directdrawsink_debug, "error flipping");
1168
1169     } else {
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);
1177
1178         } else {
1179           /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1180           hRes =
1181               IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1182               surface->surface, NULL, DDBLT_WAIT, NULL);
1183         }
1184       } else {
1185         /*blit to our primary surface */
1186         hRes =
1187             IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1188             surface->surface, NULL, DDBLT_WAIT, NULL);
1189         if (hRes != DD_OK)
1190           GST_CAT_WARNING (directdrawsink_debug,
1191               "IDirectDrawSurface_Blt returned %s", DDErrorString (hRes));
1192         else
1193           GST_CAT_INFO (directdrawsink_debug,
1194               "allocated surface was blit to our primary");
1195       }
1196     }
1197   }
1198
1199   if (ddrawsink->bUseOverlay)
1200     gst_directdrawsink_show_overlay (ddrawsink);
1201
1202   return GST_FLOW_OK;
1203 }
1204
1205 static gboolean
1206 gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1207 {
1208   gboolean bRet = TRUE;
1209   HRESULT hRes;
1210   DWORD dwCooperativeLevel;
1211   DDSURFACEDESC dd_surface_desc;
1212
1213   /*UUID IDirectDraw7_ID;
1214
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);
1219    */
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));
1224     return FALSE;
1225   }
1226
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);
1231 */
1232   /*set cooperative level */
1233   if (ddrawsink->fullscreen)
1234     dwCooperativeLevel = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
1235   else
1236     dwCooperativeLevel = DDSCL_NORMAL;
1237
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));
1243     bRet = FALSE;
1244   }
1245
1246   /*for fullscreen mode, setup display mode */
1247   if (ddrawsink->fullscreen) {
1248     hRes = IDirectDraw_SetDisplayMode (ddrawsink->ddraw_object, 1440, 900, 32);
1249   }
1250
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;
1257
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);
1264       return FALSE;
1265     }
1266
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);
1274     }
1275
1276   } else {
1277     DDSURFACEDESC desc_surface;
1278
1279     desc_surface.dwSize = sizeof (DDSURFACEDESC);
1280
1281     /*get extern surface size */
1282     hRes = IDirectDrawSurface_GetSurfaceDesc (ddrawsink->extern_surface,
1283         &desc_surface);
1284     if (hRes != DD_OK) {
1285       /*error while retrieving ext surface description */
1286       return FALSE;
1287     }
1288
1289     ddrawsink->out_width = desc_surface.dwWidth;
1290     ddrawsink->out_height = desc_surface.dwHeight;
1291
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));
1301       return FALSE;
1302     }
1303
1304     /*get specific caps if needed ... */
1305   }
1306
1307   ddrawsink->setup = TRUE;
1308
1309   return bRet;
1310 }
1311
1312 long FAR PASCAL
1313 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1314 {
1315   switch (message) {
1316       /*case WM_ERASEBKGND:
1317          return TRUE; */
1318 /*    case WM_WINDOWPOSCHANGED:
1319     case WM_MOVE:
1320     case WM_SIZE:
1321                 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1322                         gst_directdrawsink_show_overlay(global_ddrawsink);
1323                 break;
1324  case WM_PAINT:
1325                 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1326     {
1327       if(global_ddrawsink->extern_surface)
1328         gst_directdrawsink_fill_colorkey(global_ddrawsink->extern_surface, 
1329             global_ddrawsink->color_key);
1330       else
1331         gst_directdrawsink_fill_colorkey(global_ddrawsink->primary_surface, 
1332             global_ddrawsink->color_key);
1333     }
1334         break;
1335 */
1336     case WM_DESTROY:
1337       PostQuitMessage (0);
1338       break;
1339     case WM_CLOSE:
1340       DestroyWindow (hWnd);
1341       return 0;
1342   }
1343   return DefWindowProc (hWnd, message, wParam, lParam);
1344 }
1345
1346 static gpointer
1347 gst_directdrawsink_window_thread (GstDirectDrawSink * ddrawsink)
1348 {
1349   WNDCLASS WndClass;
1350
1351   memset (&WndClass, 0, sizeof (WNDCLASS));
1352
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);
1361
1362   RegisterClass (&WndClass);
1363
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);
1368
1369   if (ddrawsink->video_window == NULL)
1370     return FALSE;
1371
1372   ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1373
1374   /*start message loop processing our default window messages */
1375   while (1) {
1376     MSG msg;
1377
1378     if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
1379       break;
1380     DispatchMessage (&msg);
1381   }
1382
1383   return NULL;
1384 }
1385
1386 static gboolean
1387 gst_directdrawsink_create_default_window (GstDirectDrawSink * ddrawsink)
1388 {
1389   ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1390   if (ddrawsink->window_created_signal == NULL)
1391     return FALSE;
1392
1393   ddrawsink->window_thread = g_thread_create (
1394       (GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
1395
1396   if (ddrawsink->window_thread == NULL)
1397     goto failed;
1398
1399   /* wait maximum 10 seconds for windows creating */
1400   if (WaitForSingleObject (ddrawsink->window_created_signal,
1401           10000) != WAIT_OBJECT_0)
1402     goto failed;
1403
1404   CloseHandle (ddrawsink->window_created_signal);
1405   return TRUE;
1406
1407 failed:
1408   CloseHandle (ddrawsink->window_created_signal);
1409   return FALSE;
1410 }
1411
1412 static gboolean
1413 gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
1414 {
1415   DDSURFACEDESC dd_surface_desc;
1416   HRESULT hRes;
1417
1418   memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1419   dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1420
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));
1427
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;
1434
1435     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1436         &ddrawsink->overlays, NULL);
1437
1438     if (hRes != DD_OK) {
1439       GST_CAT_WARNING (directdrawsink_debug,
1440           "create_ddraw_surfaces:CreateSurface(overlays) failed %s",
1441           DDErrorString (hRes));
1442       return FALSE;
1443     } else {
1444       GST_CAT_INFO (directdrawsink_debug,
1445           "An overlay surfaces flipping chain was created");
1446     }
1447   } else {
1448     dd_surface_desc.ddsCaps.dwCaps =
1449         DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
1450
1451     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1452         &ddrawsink->offscreen_surface, NULL);
1453
1454     if (hRes != DD_OK) {
1455       GST_CAT_WARNING (directdrawsink_debug,
1456           "create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
1457           DDErrorString (hRes));
1458       return FALSE;
1459     }
1460   }
1461
1462   return TRUE;
1463 }
1464
1465 static void
1466 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1467     GstClockTime * start, GstClockTime * end)
1468 {
1469   GstDirectDrawSink *ddrawsink;
1470
1471   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1472
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);
1477     } else {
1478       if (ddrawsink->fps_n > 0) {
1479         *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1480       }
1481     }
1482   }
1483 }
1484
1485 static int
1486 gst_directdrawsink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1487 {
1488   gint order = 0, binary;
1489
1490   binary =
1491       lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
1492       dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
1493       dwRGBAlphaBitMask;
1494   while (binary != 0) {
1495     if ((binary % 2) == 1)
1496       order++;
1497     binary = binary >> 1;
1498   }
1499   return order;
1500 }
1501
1502 HRESULT WINAPI
1503 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1504 {
1505   GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1506   GstCaps *format_caps = NULL;
1507
1508   if (!ddrawsink || !lpDDSurfaceDesc)
1509     return DDENUMRET_CANCEL;
1510
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;
1515   }
1516
1517   if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1518     return DDENUMRET_OK;
1519
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);
1531
1532   if (format_caps) {
1533     gst_caps_append (ddrawsink->caps, format_caps);
1534   }
1535
1536   return DDENUMRET_OK;
1537 }
1538
1539 static GstCaps *
1540 gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1541 {
1542   HRESULT hRes = S_OK;
1543   DWORD dwFourccCodeIndex = 0;
1544   LPDWORD pdwFourccCodes = NULL;
1545   DWORD dwNbFourccCodes = 0;
1546   GstCaps *format_caps = NULL;
1547
1548   ddrawsink->caps = gst_caps_new_empty ();
1549   if (!ddrawsink->caps)
1550     return FALSE;
1551
1552   /*enumerate display modes exposed by directdraw object */
1553   hRes =
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));
1559     return FALSE;
1560   }
1561
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)
1567       return FALSE;
1568
1569     if (FAILED (IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object,
1570                 &dwNbFourccCodes, pdwFourccCodes))) {
1571       g_free (pdwFourccCodes);
1572       return FALSE;
1573     }
1574
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',
1580               'Y')
1581           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', 'U',
1582               '9')
1583           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', '1',
1584               '2')
1585           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('A', 'Y', 'U',
1586               'V')
1587           ) {
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);
1593
1594         if (format_caps)
1595           gst_caps_append (ddrawsink->caps, format_caps);
1596       }
1597     }
1598
1599     g_free (pdwFourccCodes);
1600   }
1601
1602   if (gst_caps_is_empty (ddrawsink->caps)) {
1603     gst_caps_unref (ddrawsink->caps);
1604
1605     GST_ELEMENT_ERROR (ddrawsink, STREAM, WRONG_TYPE, (NULL),
1606         ("No supported format found"));
1607     return NULL;
1608   }
1609
1610   return ddrawsink->caps;
1611 }
1612
1613 /* Creates miniobject and our internal surface */
1614 static GstDDrawSurface *
1615 gst_directdrawsink_surface_create (GstDirectDrawSink * ddrawsink,
1616     GstCaps * caps, size_t size)
1617 {
1618   GstDDrawSurface *surface = NULL;
1619   GstStructure *structure = NULL;
1620   gint pitch;
1621
1622   HRESULT hRes;
1623   DDSURFACEDESC surf_desc, surf_lock_desc;
1624
1625   g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1626
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);
1632
1633   /*create miniobject and initialize it */
1634   surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1635   surface->locked = FALSE;
1636
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);
1641   }
1642
1643   pitch = GST_ROUND_UP_8 (size / surface->height);
1644
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,
1648         caps);
1649   }
1650
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 */
1654
1655     surf_desc.ddsCaps.dwCaps =
1656         DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1657     surf_desc.dwFlags =
1658         DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1659     surf_desc.dwHeight = surface->height;
1660     surf_desc.dwWidth = surface->width;
1661
1662     memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1663         sizeof (DDPIXELFORMAT));
1664
1665     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1666         &surface->surface, NULL);
1667     if (hRes != DD_OK) {
1668       /*gst_object_unref (surface);
1669          surface = NULL;
1670          goto beach; */
1671       goto surface_pitch_bad;
1672     }
1673
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;
1680
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);
1685
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;
1689     }
1690
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;
1696   } else {
1697
1698   surface_pitch_bad:
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;
1702
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));
1711
1712     hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1713         DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1714 */
1715     surface->surface = NULL;
1716     /*printf ("allocating a buffer of %d bytes\n", size); */
1717   }
1718
1719   /* Keep a ref to our sink */
1720   surface->ddrawsink = gst_object_ref (ddrawsink);
1721
1722   /*
1723      beach:
1724    */
1725   return surface;
1726 }
1727
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 */
1730 static void
1731 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
1732     GstDDrawSurface * surface)
1733 {
1734   g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
1735
1736   /* Release our internal surface */
1737   if (surface->surface) {
1738     if (surface->locked) {
1739       IDirectDrawSurface_Unlock (surface->surface, NULL);
1740       surface->locked = FALSE;
1741     }
1742     IDirectDrawSurface_Release (surface->surface);
1743     surface->surface = NULL;
1744   }
1745
1746   if (GST_BUFFER (surface)->malloc_data) {
1747     g_free (GST_BUFFER (surface)->malloc_data);
1748     GST_BUFFER (surface)->malloc_data = NULL;
1749   }
1750
1751   if (!surface->ddrawsink) {
1752     goto no_sink;
1753   }
1754
1755   /* Release the ref to our sink */
1756   surface->ddrawsink = NULL;
1757   gst_object_unref (ddrawsink);
1758
1759   return;
1760
1761 no_sink:
1762   GST_WARNING ("no sink found in surface");
1763   return;
1764 }
1765
1766 static void
1767 gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
1768 {
1769   g_mutex_lock (ddrawsink->pool_lock);
1770   while (ddrawsink->buffer_pool) {
1771     GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
1772
1773     ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
1774         ddrawsink->buffer_pool);
1775     gst_directdrawsink_surface_destroy (ddrawsink, surface);
1776   }
1777   g_mutex_unlock (ddrawsink->pool_lock);
1778 }
1779
1780 static void
1781 gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink)
1782 {
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;
1789   }
1790
1791   if (ddrawsink->buffer_pool) {
1792     gst_directdrawsink_bufferpool_clear (ddrawsink);
1793     ddrawsink->buffer_pool = NULL;
1794   }
1795
1796   if (ddrawsink->display_modes) {
1797     GSList *walk = ddrawsink->display_modes;
1798
1799     while (walk) {
1800       g_free (walk->data);
1801       walk = g_slist_next (walk);
1802     }
1803     g_slist_free (ddrawsink->display_modes);
1804     ddrawsink->display_modes = NULL;
1805   }
1806
1807   if (ddrawsink->overlays) {
1808     IDirectDrawSurface_Release (ddrawsink->overlays);
1809     ddrawsink->overlays = NULL;
1810   }
1811
1812   if (ddrawsink->offscreen_surface) {
1813     IDirectDrawSurface_Release (ddrawsink->offscreen_surface);
1814     ddrawsink->offscreen_surface = NULL;
1815   }
1816
1817   if (ddrawsink->clipper) {
1818     IDirectDrawClipper_Release (ddrawsink->clipper);
1819     ddrawsink->clipper = NULL;
1820   }
1821
1822   if (ddrawsink->primary_surface) {
1823     IDirectDrawSurface_Release (ddrawsink->primary_surface);
1824     ddrawsink->primary_surface = NULL;
1825   }
1826
1827   if (ddrawsink->ddraw_object) {
1828     IDirectDraw_Release (ddrawsink->ddraw_object);
1829     ddrawsink->ddraw_object = NULL;
1830   }
1831
1832   ddrawsink->setup = FALSE;
1833 }