sys/: Wait until the window is created before using it; guard unistd.h includes with...
[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 static GstCaps *
172 gst_ddrawvideosink_get_caps_from_format (DDPIXELFORMAT pixel_format)
173 {
174   GstCaps *caps = NULL;
175   gint bpp, depth;
176   guint32 fourcc;
177
178   if ((pixel_format.dwFlags & DDPF_RGB) == DDPF_RGB) {
179     bpp = pixel_format.dwRGBBitCount;
180     if (bpp != 32)
181       depth = bpp;
182     else {
183       if ((pixel_format.dwFlags & DDPF_ALPHAPREMULT) == DDPF_ALPHAPREMULT)
184         depth = 32;
185       else
186         depth = 24;
187     }
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);
192   }
193
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);
198   }
199
200   g_assert (caps != NULL);
201
202   return caps;
203 }
204
205 static void
206 gst_directdrawsink_center_rect (RECT src, RECT dst, RECT * result)
207 {
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;
214
215   g_return_if_fail (result != NULL);
216
217   src_ratio = (gdouble) src_width / src_height;
218   dst_ratio = (gdouble) dst_width / dst_heigth;
219
220   if (src_ratio > dst_ratio) {
221     /*new height */
222     result_height = (long) (dst_width / src_ratio);
223
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;
228
229   } else if (src_ratio < dst_ratio) {
230     /*new width */
231     result_width = (long) (dst_heigth * src_ratio);
232
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;
237
238   } else {
239     /*same ratio */
240     memcpy (result, &dst, sizeof (RECT));
241   }
242
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,
247       result->right);
248 }
249
250 /*subclass of GstBuffer which manages surfaces lifetime*/
251 static void
252 gst_ddrawsurface_finalize (GstDDrawSurface * surface)
253 {
254   GstDirectDrawSink *ddrawsink = NULL;
255
256   g_return_if_fail (surface != NULL);
257
258   ddrawsink = surface->ddrawsink;
259   if (!ddrawsink)
260     goto no_sink;
261
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)
267       ) {
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);
273
274   } else {
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");
277
278     /* need to increment the refcount again to recycle */
279     gst_buffer_ref (GST_BUFFER (surface));
280
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);
284   }
285   return;
286
287 no_sink:
288   GST_CAT_WARNING (directdrawsink_debug, "no sink found");
289   return;
290 }
291
292 static void
293 gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
294 {
295   surface->surface = NULL;
296   surface->width = 0;
297   surface->height = 0;
298   surface->ddrawsink = NULL;
299   surface->locked = FALSE;
300   surface->system_memory = FALSE;
301   memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
302 }
303
304 static void
305 gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
306 {
307   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
308
309   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
310       gst_ddrawsurface_finalize;
311 }
312
313 GType
314 gst_ddrawsurface_get_type (void)
315 {
316   static GType _gst_ddrawsurface_type;
317
318   if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
319     static const GTypeInfo ddrawsurface_info = {
320       sizeof (GstBufferClass),
321       NULL,
322       NULL,
323       gst_ddrawsurface_class_init,
324       NULL,
325       NULL,
326       sizeof (GstDDrawSurface),
327       0,
328       (GInstanceInitFunc) gst_ddrawsurface_init,
329       NULL
330     };
331     _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
332         "GstDDrawSurface", &ddrawsurface_info, 0);
333   }
334   return _gst_ddrawsurface_type;
335 }
336
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; */
340
341 /*GType
342 gst_directdrawsink_get_type (void)
343 {
344   static GType directdrawsink_type = 0;
345
346   if (!directdrawsink_type) {
347     static const GTypeInfo directdrawsink_info = {
348       sizeof (GstDirectDrawSinkClass),
349       gst_directdrawsink_base_init,
350       NULL,
351       (GClassInitFunc) gst_directdrawsink_class_init,
352       NULL,
353       NULL,
354       sizeof (GstDirectDrawSink),
355       0,
356       (GInstanceInitFunc) gst_directdrawsink_init,
357     };
358
359     directdrawsink_type =
360         g_type_register_static (GST_TYPE_VIDEO_SINK, "GstDirectDrawSink",
361         &directdrawsink_info, 0);
362   }
363
364   return directdrawsink_type;
365 }
366 */
367 static void
368 gst_directdrawsink_base_init (gpointer g_class)
369 {
370   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
371
372   gst_element_class_set_details (element_class, &gst_directdrawsink_details);
373
374   gst_element_class_add_pad_template (element_class,
375       gst_static_pad_template_get (&directdrawsink_sink_factory));
376 }
377
378 static void
379 gst_directdrawsink_class_init (GstDirectDrawSinkClass * klass)
380 {
381   GObjectClass *gobject_class;
382   GstElementClass *gstelement_class;
383   GstBaseSinkClass *gstbasesink_class;
384
385   gobject_class = (GObjectClass *) klass;
386   gstbasesink_class = (GstBaseSinkClass *) klass;
387   gstelement_class = (GstElementClass *) klass;
388
389   GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
390       "Direct draw sink");
391
392   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdrawsink_finalize);
393
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);
398
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);
406
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);
411
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));
416
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,
421           G_PARAM_WRITABLE));
422
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));
427
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,
432           G_PARAM_READWRITE));
433
434   /*should add a color_key property to permit applications to define the color used for overlays */
435 }
436
437 static void
438 gst_directdrawsink_set_property (GObject * object, guint prop_id,
439     const GValue * value, GParamSpec * pspec)
440 {
441   GstDirectDrawSink *ddrawsink;
442
443   ddrawsink = GST_DIRECTDRAW_SINK (object);
444
445   switch (prop_id) {
446     case PROP_SURFACE:
447       ddrawsink->extern_surface = g_value_get_pointer (value);
448       break;
449     case PROP_WINDOW:
450       ddrawsink->video_window = (HWND) g_value_get_long (value);
451       ddrawsink->resize_window = FALSE;
452       break;
453     case PROP_FULLSCREEN:
454       /*ddrawsink->fullscreen = g_value_get_boolean (value); not working .... */
455       break;
456     case PROP_KEEP_ASPECT_RATIO:
457       ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
458       break;
459     default:
460       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
461       break;
462   }
463 }
464
465 static void
466 gst_directdrawsink_get_property (GObject * object, guint prop_id,
467     GValue * value, GParamSpec * pspec)
468 {
469   GstDirectDrawSink *ddrawsink;
470
471   ddrawsink = GST_DIRECTDRAW_SINK (object);
472
473   switch (prop_id) {
474     case PROP_FULLSCREEN:
475       g_value_set_boolean (value, ddrawsink->fullscreen);
476       break;
477     case PROP_KEEP_ASPECT_RATIO:
478       g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
479       break;
480     default:
481       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
482       break;
483   }
484 }
485
486 static void
487 gst_directdrawsink_finalize (GObject * object)
488 {
489   GstDirectDrawSink *ddrawsink;
490
491   ddrawsink = GST_DIRECTDRAW_SINK (object);
492
493   if (ddrawsink->pool_lock) {
494     g_mutex_free (ddrawsink->pool_lock);
495     ddrawsink->pool_lock = NULL;
496   }
497   if (ddrawsink->setup) {
498     gst_directdrawsink_cleanup (ddrawsink);
499   }
500 }
501
502 static void
503 gst_directdrawsink_init (GstDirectDrawSink * ddrawsink,
504     GstDirectDrawSinkClass * g_class)
505 {
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;
512
513   /*video default values */
514   ddrawsink->video_height = 0;
515   ddrawsink->video_width = 0;
516   ddrawsink->fps_n = 0;
517   ddrawsink->fps_d = 0;
518
519   memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
520
521   ddrawsink->caps = NULL;
522
523   ddrawsink->window_thread = NULL;
524
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 ... */
527
528   ddrawsink->fullscreen = FALSE;
529   ddrawsink->setup = FALSE;
530
531   ddrawsink->display_modes = NULL;
532   ddrawsink->buffer_pool = NULL;
533
534   ddrawsink->resize_window = TRUE;      /*resize only our internal window to the video size */
535
536   ddrawsink->pool_lock = g_mutex_new ();
537
538   ddrawsink->keep_aspect_ratio = TRUE;
539 /*  ddrawsink->can_blit = TRUE;*/
540 }
541
542 static GstCaps *
543 gst_directdrawsink_get_caps (GstBaseSink * bsink)
544 {
545   GstDirectDrawSink *ddrawsink;
546   GstCaps *caps = NULL;
547
548   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
549
550   if (!ddrawsink->setup) {
551     caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
552             (ddrawsink)));
553
554     GST_CAT_INFO (directdrawsink_debug,
555         "getcaps called and we are not setup yet, " "returning template %"
556         GST_PTR_FORMAT, caps);
557   } else {
558     /*if (ddrawsink->extern_surface) {
559      * We are not rendering to our own surface, returning this surface's
560      *  pixel format *
561      GST_WARNING ("using extern surface");
562      caps = gst_ddrawvideosink_get_caps_from_format (ddrawsink->dd_pixel_format);
563      } else */
564
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);
568   }
569
570   return caps;
571 }
572
573 static gboolean
574 gst_directdrawsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
575 {
576   GstDirectDrawSink *ddrawsink;
577   GstStructure *structure = NULL;
578   gboolean ret;
579   const GValue *fps;
580
581   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
582
583   structure = gst_caps_get_structure (caps, 0);
584   if (!structure)
585     return FALSE;
586
587   ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
588   ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
589
590   fps = gst_structure_get_value (structure, "framerate");
591   ret &= (fps != NULL);
592
593   ret &=
594       gst_ddrawvideosink_get_format_from_caps (caps,
595       &ddrawsink->dd_pixel_format);
596
597   if (!ret)
598     return FALSE;
599
600   ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
601   ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
602
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);
608   }
609
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);
617     if (ret) {
618       return TRUE;
619     }
620
621     /*could not create draw surfaces even with fallback, so leave
622        everything as is */
623     ddrawsink->bUseOverlay = TRUE;
624   }
625   if (!ret) {
626     GST_CAT_ERROR (directdrawsink_debug, "Can not create ddraw surface");
627   }
628   return ret;
629 }
630
631 static GstStateChangeReturn
632 gst_directdrawsink_change_state (GstElement * element,
633     GstStateChange transition)
634 {
635   GstDirectDrawSink *ddrawsink;
636
637   ddrawsink = GST_DIRECTDRAW_SINK (element);
638
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;
644
645       if (!gst_directdrawsink_setup_ddraw (ddrawsink))
646         return GST_STATE_CHANGE_FAILURE;
647
648       if (!(ddrawsink->caps = gst_directdrawsink_get_ddrawcaps (ddrawsink)))
649         return GST_STATE_CHANGE_FAILURE;
650
651       break;
652     case GST_STATE_CHANGE_READY_TO_PAUSED:
653       break;
654     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
655       break;
656     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
657       break;
658     case GST_STATE_CHANGE_PAUSED_TO_READY:
659
660       ddrawsink->fps_n = 0;
661       ddrawsink->fps_d = 1;
662       ddrawsink->video_width = 0;
663       ddrawsink->video_height = 0;
664
665       if (ddrawsink->buffer_pool)
666         gst_directdrawsink_bufferpool_clear (ddrawsink);
667
668       break;
669     case GST_STATE_CHANGE_READY_TO_NULL:
670
671       if (ddrawsink->setup)
672         gst_directdrawsink_cleanup (ddrawsink);
673
674       break;
675   }
676
677   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
678 }
679
680 /**
681  * Get DirectDraw error message.
682  * @hr: HRESULT code
683  * Returns: Text representation of the error.
684  */
685 char *
686 DDErrorString (HRESULT hr)
687 {
688   switch (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";
699     case DDERR_GENERIC:
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";
721     case DDERR_NO3D:
722       return "DDERR_NO3D";
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";
739     case DDERR_NOFLIPHW:
740       return "DDERR_NOFLIPHW";
741     case DDERR_NOGDI:
742       return "DDERR_NOGDI";
743     case DDERR_NOMIRRORHW:
744       return "DDERR_NOMIRRORHW";
745     case DDERR_NOTFOUND:
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";
813     case DDERR_XALIGN:
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";
831     case DDERR_NOHWND:
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";
843     case DDERR_NOBLTHW:
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";
865     case DDERR_NODC:
866       return "DDERR_NODC";
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";
889   }
890   return "Unknown Error";
891 }
892
893
894 static GstFlowReturn
895 gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
896     guint size, GstCaps * caps, GstBuffer ** buf)
897 {
898   GstDirectDrawSink *ddrawsink = NULL;
899   GstDDrawSurface *surface = NULL;
900   GstStructure *structure = NULL;
901   GstFlowReturn ret = GST_FLOW_OK;
902
903   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
904   GST_CAT_INFO (directdrawsink_debug, "a buffer of %d bytes was requested",
905       size);
906
907   structure = gst_caps_get_structure (caps, 0);
908
909   g_mutex_lock (ddrawsink->pool_lock);
910
911   /* Inspect our buffer pool */
912   while (ddrawsink->buffer_pool) {
913     surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
914
915     if (surface) {
916       /* Removing from the pool */
917       ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
918           ddrawsink->buffer_pool);
919
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)))
925           ) {
926         gst_directdrawsink_surface_destroy (ddrawsink, surface);
927         surface = NULL;
928       } else {
929         /* We found a suitable surface */
930         break;
931       }
932     }
933   }
934
935   /* We haven't found anything, creating a new one */
936   if (!surface) {
937     surface = gst_directdrawsink_surface_create (ddrawsink, caps, size);
938   }
939
940   /* Now we should have a surface, set appropriate caps on it */
941   if (surface) {
942     gst_buffer_set_caps (GST_BUFFER (surface), caps);
943   }
944
945   g_mutex_unlock (ddrawsink->pool_lock);
946
947   *buf = GST_BUFFER (surface);
948
949   return ret;
950 }
951
952 static gboolean
953 gst_directdrawsink_fill_colorkey (LPDIRECTDRAWSURFACE surface, DWORD dwColorKey)
954 {
955   DDBLTFX ddbfx;
956
957   if (!surface)
958     return FALSE;
959
960   ddbfx.dwSize = sizeof (DDBLTFX);
961   ddbfx.dwFillColor = dwColorKey;
962
963   if (IDirectDrawSurface_Blt (surface,
964           NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx) == DD_OK)
965     return TRUE;
966   else
967     return FALSE;
968 }
969
970
971 static void
972 gst_directdrawsink_show_overlay (GstDirectDrawSink * ddrawsink)
973 {
974   HRESULT hRes;
975   RECT destsurf_rect, src_rect;
976   POINT dest_surf_point;
977   DDOVERLAYFX ddofx;
978   LPDIRECTDRAWSURFACE surface = NULL;
979
980   if (!ddrawsink || !ddrawsink->overlays)
981     return;
982
983   if (ddrawsink->extern_surface)
984     surface = ddrawsink->extern_surface;
985   else
986     surface = ddrawsink->primary_surface;
987
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;
993   } else {
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);
999   }
1000
1001   if (ddrawsink->keep_aspect_ratio) {
1002     src_rect.top = 0;
1003     src_rect.left = 0;
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);
1007   }
1008
1009   gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
1010
1011   ddofx.dwSize = sizeof (DDOVERLAYFX);
1012   ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
1013   ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
1014
1015   hRes = IDirectDrawSurface_UpdateOverlay (ddrawsink->overlays,
1016       NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
1017       &ddofx);
1018 }
1019
1020 static GstFlowReturn
1021 gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
1022 {
1023   GstDirectDrawSink *ddrawsink;
1024   HRESULT hRes;
1025
1026   DDSURFACEDESC surf_desc;
1027   RECT destsurf_rect, src_rect;
1028   POINT dest_surf_point;
1029   LPDIRECTDRAWSURFACE lpSurface = NULL;
1030
1031   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1032
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;
1038   } else {
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);
1044   }
1045
1046   if (ddrawsink->keep_aspect_ratio) {
1047     /*center image to dest image keeping aspect ratio */
1048     src_rect.top = 0;
1049     src_rect.left = 0;
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);
1053   }
1054
1055   if (ddrawsink->bUseOverlay) {
1056     /*get the back buffer of the overlays flipping chain */
1057     DDSCAPS ddbackcaps;
1058
1059     ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
1060     IDirectDrawSurface_GetAttachedSurface (ddrawsink->overlays, &ddbackcaps,
1061         &lpSurface);
1062   } else {
1063     /*use our offscreen surface */
1064     lpSurface = ddrawsink->offscreen_surface;
1065   }
1066
1067   if (lpSurface == NULL)
1068     return GST_FLOW_ERROR;
1069
1070   if (!GST_IS_DDRAWSURFACE (buf) ||
1071       ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
1072
1073     LPBYTE data = NULL;
1074     guint src_pitch, line;
1075
1076     /* Check for lost surface */
1077     if (IDirectDrawSurface_IsLost (lpSurface) == DDERR_SURFACELOST) {
1078       IDirectDrawSurface_Restore (lpSurface);
1079     }
1080
1081     ZeroMemory (&surf_desc, sizeof (surf_desc));
1082     surf_desc.dwSize = sizeof (surf_desc);
1083
1084     /* Lock the surface */
1085     hRes =
1086         IDirectDrawSurface_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
1087         NULL);
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;
1093     }
1094
1095     /* Write data */
1096     data = surf_desc.lpSurface;
1097
1098     /* Source video rowbytes */
1099     src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
1100
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;
1105     }
1106
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;
1114     }
1115
1116     if (ddrawsink->bUseOverlay) {
1117       /*Flip to front overlay */
1118       hRes =
1119           IDirectDrawSurface_Flip (ddrawsink->overlays, lpSurface, DDFLIP_WAIT);
1120       IDirectDrawSurface_Release (lpSurface);
1121       lpSurface = NULL;
1122     } else {
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);
1129
1130         } else {
1131           /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1132           hRes =
1133               IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1134               lpSurface, NULL, DDBLT_WAIT, NULL);
1135         }
1136       } else {
1137         /*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
1138         hRes =
1139             IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1140             lpSurface, NULL, DDBLT_WAIT, NULL);
1141       }
1142     }
1143   } else {
1144
1145     GstDDrawSurface *surface = NULL;
1146
1147     surface = GST_DDRAWSURFACE (buf);
1148
1149     /* Unlocking surface before blit */
1150     IDirectDrawSurface_Unlock (surface->surface, NULL);
1151     surface->locked = FALSE;
1152
1153     /* Check for lost surfaces */
1154     if (IDirectDrawSurface_IsLost (surface->surface) == DDERR_SURFACELOST) {
1155       IDirectDrawSurface_Restore (surface->surface);
1156     }
1157
1158     if (ddrawsink->bUseOverlay) {
1159       /* blit to the overlays back buffer */
1160       hRes = IDirectDrawSurface_Blt (lpSurface, NULL,
1161           surface->surface, NULL, DDBLT_WAIT, NULL);
1162
1163       hRes = IDirectDrawSurface_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
1164       if (hRes != DD_OK)
1165         GST_CAT_WARNING (directdrawsink_debug, "error flipping");
1166
1167     } else {
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);
1175
1176         } else {
1177           /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
1178           hRes =
1179               IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
1180               surface->surface, NULL, DDBLT_WAIT, NULL);
1181         }
1182       } else {
1183         /*blit to our primary surface */
1184         hRes =
1185             IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
1186             surface->surface, NULL, DDBLT_WAIT, NULL);
1187         if (hRes != DD_OK)
1188           GST_CAT_WARNING (directdrawsink_debug,
1189               "IDirectDrawSurface_Blt returned %s", DDErrorString (hRes));
1190         else
1191           GST_CAT_INFO (directdrawsink_debug,
1192               "allocated surface was blit to our primary",
1193               DDErrorString (hRes));
1194       }
1195     }
1196   }
1197
1198   if (ddrawsink->bUseOverlay)
1199     gst_directdrawsink_show_overlay (ddrawsink);
1200
1201   return GST_FLOW_OK;
1202 }
1203
1204 static gboolean
1205 gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink)
1206 {
1207   gboolean bRet = TRUE;
1208   HRESULT hRes;
1209   DWORD dwCooperativeLevel;
1210   DDSURFACEDESC dd_surface_desc;
1211
1212   /*UUID IDirectDraw7_ID;
1213
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);
1218    */
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));
1223     return FALSE;
1224   }
1225
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);
1230 */
1231   /*set cooperative level */
1232   if (ddrawsink->fullscreen)
1233     dwCooperativeLevel = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
1234   else
1235     dwCooperativeLevel = DDSCL_NORMAL;
1236
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));
1242     bRet = FALSE;
1243   }
1244
1245   /*for fullscreen mode, setup display mode */
1246   if (ddrawsink->fullscreen) {
1247     hRes = IDirectDraw_SetDisplayMode (ddrawsink->ddraw_object, 1440, 900, 32);
1248   }
1249
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;
1256
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);
1263       return FALSE;
1264     }
1265
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);
1273     }
1274
1275   } else {
1276     DDSURFACEDESC desc_surface;
1277
1278     desc_surface.dwSize = sizeof (DDSURFACEDESC);
1279
1280     /*get extern surface size */
1281     hRes = IDirectDrawSurface_GetSurfaceDesc (ddrawsink->extern_surface,
1282         &desc_surface);
1283     if (hRes != DD_OK) {
1284       /*error while retrieving ext surface description */
1285       return FALSE;
1286     }
1287
1288     ddrawsink->out_width = desc_surface.dwWidth;
1289     ddrawsink->out_height = desc_surface.dwHeight;
1290
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));
1300       return FALSE;
1301     }
1302
1303     /*get specific caps if needed ... */
1304   }
1305
1306   ddrawsink->setup = TRUE;
1307
1308   return bRet;
1309 }
1310
1311 long FAR PASCAL
1312 WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1313 {
1314   switch (message) {
1315       /*case WM_ERASEBKGND:
1316          return TRUE; */
1317 /*    case WM_WINDOWPOSCHANGED:
1318     case WM_MOVE:
1319     case WM_SIZE:
1320                 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1321                         gst_directdrawsink_show_overlay(global_ddrawsink);
1322                 break;
1323  case WM_PAINT:
1324                 if(global_ddrawsink && global_ddrawsink->bUseOverlay)
1325     {
1326       if(global_ddrawsink->extern_surface)
1327         gst_directdrawsink_fill_colorkey(global_ddrawsink->extern_surface, 
1328             global_ddrawsink->color_key);
1329       else
1330         gst_directdrawsink_fill_colorkey(global_ddrawsink->primary_surface, 
1331             global_ddrawsink->color_key);
1332     }
1333         break;
1334 */
1335     case WM_DESTROY:
1336       PostQuitMessage (0);
1337       break;
1338     case WM_CLOSE:
1339       DestroyWindow (hWnd);
1340       return 0;
1341   }
1342   return DefWindowProc (hWnd, message, wParam, lParam);
1343 }
1344
1345 static gpointer
1346 gst_directdrawsink_window_thread (GstDirectDrawSink * ddrawsink)
1347 {
1348   WNDCLASS WndClass;
1349
1350   memset (&WndClass, 0, sizeof (WNDCLASS));
1351
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);
1360
1361   RegisterClass (&WndClass);
1362
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);
1367
1368   if (ddrawsink->video_window == NULL)
1369     return FALSE;
1370
1371   ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
1372
1373   /*start message loop processing our default window messages */
1374   while (1) {
1375     MSG msg;
1376
1377     if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
1378       break;
1379     DispatchMessage (&msg);
1380   }
1381
1382   return NULL;
1383 }
1384
1385 static gboolean
1386 gst_directdrawsink_create_default_window (GstDirectDrawSink * ddrawsink)
1387 {
1388   ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
1389   if (ddrawsink->window_created_signal == NULL)
1390     return FALSE;
1391
1392   ddrawsink->window_thread = g_thread_create (
1393       (GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
1394
1395   if (ddrawsink->window_thread == NULL)
1396     goto failed;
1397
1398   /* wait maximum 10 seconds for windows creating */
1399   if (WaitForSingleObject (ddrawsink->window_created_signal,
1400           10000) != WAIT_OBJECT_0)
1401     goto failed;
1402
1403   CloseHandle (ddrawsink->window_created_signal);
1404   return TRUE;
1405
1406 failed:
1407   CloseHandle (ddrawsink->window_created_signal);
1408   return FALSE;
1409 }
1410
1411 static gboolean
1412 gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
1413 {
1414   DDSURFACEDESC dd_surface_desc;
1415   HRESULT hRes;
1416
1417   memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
1418   dd_surface_desc.dwSize = sizeof (dd_surface_desc);
1419
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));
1426
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;
1433
1434     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1435         &ddrawsink->overlays, NULL);
1436
1437     if (hRes != DD_OK) {
1438       GST_CAT_WARNING (directdrawsink_debug,
1439           "create_ddraw_surfaces:CreateSurface(overlays) failed %s",
1440           DDErrorString (hRes));
1441       return FALSE;
1442     } else {
1443       GST_CAT_INFO (directdrawsink_debug,
1444           "An overlay surfaces flipping chain was created");
1445     }
1446   } else {
1447     dd_surface_desc.ddsCaps.dwCaps =
1448         DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
1449
1450     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
1451         &ddrawsink->offscreen_surface, NULL);
1452
1453     if (hRes != DD_OK) {
1454       GST_CAT_WARNING (directdrawsink_debug,
1455           "create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
1456           DDErrorString (hRes));
1457       return FALSE;
1458     }
1459   }
1460
1461   return TRUE;
1462 }
1463
1464 static void
1465 gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
1466     GstClockTime * start, GstClockTime * end)
1467 {
1468   GstDirectDrawSink *ddrawsink;
1469
1470   ddrawsink = GST_DIRECTDRAW_SINK (bsink);
1471
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);
1476     } else {
1477       if (ddrawsink->fps_n > 0) {
1478         *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
1479       }
1480     }
1481   }
1482 }
1483
1484 static int
1485 gst_directdrawsink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
1486 {
1487   gint order = 0, binary;
1488
1489   binary =
1490       lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
1491       dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
1492       dwRGBAlphaBitMask;
1493   while (binary != 0) {
1494     if ((binary % 2) == 1)
1495       order++;
1496     binary = binary >> 1;
1497   }
1498   return order;
1499 }
1500
1501 HRESULT WINAPI
1502 EnumModesCallback2 (LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext)
1503 {
1504   GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
1505   GstCaps *format_caps = NULL;
1506
1507   if (!ddrawsink || !lpDDSurfaceDesc)
1508     return DDENUMRET_CANCEL;
1509
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;
1514   }
1515
1516   if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
1517     return DDENUMRET_OK;
1518
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);
1530
1531   if (format_caps) {
1532     gst_caps_append (ddrawsink->caps, format_caps);
1533   }
1534
1535   return DDENUMRET_OK;
1536 }
1537
1538 static GstCaps *
1539 gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
1540 {
1541   HRESULT hRes = S_OK;
1542   DWORD dwFourccCodeIndex = 0;
1543   LPDWORD pdwFourccCodes = NULL;
1544   DWORD dwNbFourccCodes = 0;
1545   GstCaps *format_caps = NULL;
1546
1547   ddrawsink->caps = gst_caps_new_empty ();
1548   if (!ddrawsink->caps)
1549     return FALSE;
1550
1551   /*enumerate display modes exposed by directdraw object */
1552   hRes =
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));
1558     return FALSE;
1559   }
1560
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)
1566       return FALSE;
1567
1568     if (FAILED (IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object,
1569                 &dwNbFourccCodes, pdwFourccCodes))) {
1570       g_free (pdwFourccCodes);
1571       return FALSE;
1572     }
1573
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',
1579               'Y')
1580           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', 'U',
1581               '9')
1582           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', '1',
1583               '2')
1584           || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('A', 'Y', 'U',
1585               'V')
1586           ) {
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);
1592
1593         if (format_caps)
1594           gst_caps_append (ddrawsink->caps, format_caps);
1595       }
1596     }
1597
1598     g_free (pdwFourccCodes);
1599   }
1600
1601   if (gst_caps_is_empty (ddrawsink->caps)) {
1602     gst_caps_unref (ddrawsink->caps);
1603
1604     GST_ELEMENT_ERROR (ddrawsink, STREAM, WRONG_TYPE, (NULL),
1605         ("No supported format found"));
1606     return NULL;
1607   }
1608
1609   return ddrawsink->caps;
1610 }
1611
1612 /* Creates miniobject and our internal surface */
1613 static GstDDrawSurface *
1614 gst_directdrawsink_surface_create (GstDirectDrawSink * ddrawsink,
1615     GstCaps * caps, size_t size)
1616 {
1617   GstDDrawSurface *surface = NULL;
1618   GstStructure *structure = NULL;
1619   gint pitch;
1620
1621   HRESULT hRes;
1622   DDSURFACEDESC surf_desc, surf_lock_desc;
1623
1624   g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
1625
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);
1631
1632   /*create miniobject and initialize it */
1633   surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
1634   surface->locked = FALSE;
1635
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);
1640   }
1641
1642   pitch = GST_ROUND_UP_8 (size / surface->height);
1643
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,
1647         caps);
1648   }
1649
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 */
1653
1654     surf_desc.ddsCaps.dwCaps =
1655         DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
1656     surf_desc.dwFlags =
1657         DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
1658     surf_desc.dwHeight = surface->height;
1659     surf_desc.dwWidth = surface->width;
1660
1661     memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
1662         sizeof (DDPIXELFORMAT));
1663
1664     hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
1665         &surface->surface, NULL);
1666     if (hRes != DD_OK) {
1667       /*gst_object_unref (surface);
1668          surface = NULL;
1669          goto beach; */
1670       goto surface_pitch_bad;
1671     }
1672
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;
1679
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);
1684
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;
1688     }
1689
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;
1695   } else {
1696
1697   surface_pitch_bad:
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;
1701
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));
1710
1711     hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
1712         DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
1713 */
1714     surface->surface = NULL;
1715     /*printf ("allocating a buffer of %d bytes\n", size); */
1716   }
1717
1718   /* Keep a ref to our sink */
1719   surface->ddrawsink = gst_object_ref (ddrawsink);
1720
1721 beach:
1722   return surface;
1723 }
1724
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 */
1727 static void
1728 gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
1729     GstDDrawSurface * surface)
1730 {
1731   g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
1732
1733   /* Release our internal surface */
1734   if (surface->surface) {
1735     if (surface->locked) {
1736       IDirectDrawSurface_Unlock (surface->surface, NULL);
1737       surface->locked = FALSE;
1738     }
1739     IDirectDrawSurface_Release (surface->surface);
1740     surface->surface = NULL;
1741   }
1742
1743   if (GST_BUFFER (surface)->malloc_data) {
1744     g_free (GST_BUFFER (surface)->malloc_data);
1745     GST_BUFFER (surface)->malloc_data = NULL;
1746   }
1747
1748   if (!surface->ddrawsink) {
1749     goto no_sink;
1750   }
1751
1752   /* Release the ref to our sink */
1753   surface->ddrawsink = NULL;
1754   gst_object_unref (ddrawsink);
1755
1756   return;
1757
1758 no_sink:
1759   GST_WARNING ("no sink found in surface");
1760   return;
1761 }
1762
1763 static void
1764 gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
1765 {
1766   g_mutex_lock (ddrawsink->pool_lock);
1767   while (ddrawsink->buffer_pool) {
1768     GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
1769
1770     ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
1771         ddrawsink->buffer_pool);
1772     gst_directdrawsink_surface_destroy (ddrawsink, surface);
1773   }
1774   g_mutex_unlock (ddrawsink->pool_lock);
1775 }
1776
1777 static void
1778 gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink)
1779 {
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;
1786   }
1787
1788   if (ddrawsink->buffer_pool) {
1789     gst_directdrawsink_bufferpool_clear (ddrawsink);
1790     ddrawsink->buffer_pool = NULL;
1791   }
1792
1793   if (ddrawsink->display_modes) {
1794     GSList *walk = ddrawsink->display_modes;
1795
1796     while (walk) {
1797       g_free (walk->data);
1798       walk = g_slist_next (walk);
1799     }
1800     g_slist_free (ddrawsink->display_modes);
1801     ddrawsink->display_modes = NULL;
1802   }
1803
1804   if (ddrawsink->overlays) {
1805     IDirectDrawSurface_Release (ddrawsink->overlays);
1806     ddrawsink->overlays = NULL;
1807   }
1808
1809   if (ddrawsink->offscreen_surface) {
1810     IDirectDrawSurface_Release (ddrawsink->offscreen_surface);
1811     ddrawsink->offscreen_surface = NULL;
1812   }
1813
1814   if (ddrawsink->clipper) {
1815     IDirectDrawClipper_Release (ddrawsink->clipper);
1816     ddrawsink->clipper = NULL;
1817   }
1818
1819   if (ddrawsink->primary_surface) {
1820     IDirectDrawSurface_Release (ddrawsink->primary_surface);
1821     ddrawsink->primary_surface = NULL;
1822   }
1823
1824   if (ddrawsink->ddraw_object) {
1825     IDirectDraw_Release (ddrawsink->ddraw_object);
1826     ddrawsink->ddraw_object = NULL;
1827   }
1828
1829   ddrawsink->setup = FALSE;
1830 }