summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Moutte <sebastien@moutte.net>2006-01-05 23:17:44 +0000
committerJan Schmidt <thaytan@noraisin.net>2009-05-16 01:29:14 +0100
commit4b4b81c3e5eca940776492e0908b82c642fd3eb9 (patch)
treed3fd90810d354aa13b59b59d0cb199ae0e654be7
parent90aa8eff4c553a9be1e644b424116c0280e0abfa (diff)
[MOVED FROM GOOD] added sys/directdraw added sys/directsound added win32/vs6/gst_plugins_bad.dsw added win32/vs6/libgstdirectsound.dsp ...
Original commit message from CVS: 2006-01-05 Sebastien Moutte <sebastien@moutte.net> * added sys/directdraw * added sys/directsound * added win32/vs6/gst_plugins_bad.dsw * added win32/vs6/libgstdirectsound.dsp * added win32/vs6/libgstdirectdraw.dsp * added win32/common/config.h
-rw-r--r--sys/directdraw/gstdirectdrawplugin.c42
-rw-r--r--sys/directdraw/gstdirectdrawsink.c1733
-rw-r--r--sys/directdraw/gstdirectdrawsink.h132
3 files changed, 1907 insertions, 0 deletions
diff --git a/sys/directdraw/gstdirectdrawplugin.c b/sys/directdraw/gstdirectdrawplugin.c
new file mode 100644
index 000000000..69d795074
--- /dev/null
+++ b/sys/directdraw/gstdirectdrawplugin.c
@@ -0,0 +1,42 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstdirectdrawplugin.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdirectdrawsink.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "directdrawsink", GST_RANK_NONE,
+ GST_TYPE_DIRECTDRAW_SINK))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "directdraw",
+ "DIRECTDRAW plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)
diff --git a/sys/directdraw/gstdirectdrawsink.c b/sys/directdraw/gstdirectdrawsink.c
new file mode 100644
index 000000000..55a0d54a1
--- /dev/null
+++ b/sys/directdraw/gstdirectdrawsink.c
@@ -0,0 +1,1733 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* Based on directfb video sink
+* gstdirectdrawsink.c:
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstdirectdrawsink.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
+#define GST_CAT_DEFAULT directdrawsink_debug
+
+/* elementfactory information */
+static GstElementDetails gst_directdrawsink_details =
+GST_ELEMENT_DETAILS ("Video Sink (DIRECTDRAW)",
+ "Sink/Video",
+ "Output to a video card via DIRECTDRAW",
+ "Sebastien Moutte <sebastien@moutte.net>");
+
+static void
+_do_init (GType directdrawsink_type)
+{
+ GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
+ "Direct draw sink");
+}
+
+GST_BOILERPLATE_FULL (GstDirectDrawSink, gst_directdrawsink, GstVideoSink,
+ GST_TYPE_VIDEO_SINK, _do_init);
+
+static void gst_directdrawsink_finalize (GObject * object);
+
+static void gst_directdrawsink_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_directdrawsink_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_directdrawsink_get_caps (GstBaseSink * bsink);
+static gboolean gst_directdrawsink_set_caps (GstBaseSink * bsink,
+ GstCaps * caps);
+
+static GstStateChangeReturn
+gst_directdrawsink_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstFlowReturn
+gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
+ guint size, GstCaps * caps, GstBuffer ** buf);
+
+static void
+gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+ GstClockTime * start, GstClockTime * end);
+
+static GstFlowReturn
+gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf);
+
+static gboolean gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink);
+static gboolean gst_directdrawsink_create_default_window (GstDirectDrawSink *
+ ddrawsink);
+static gboolean gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink *
+ ddrawsink);
+
+static GstCaps *gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink *
+ ddrawsink);
+
+static void gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink);
+static void gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink);
+
+
+/*surfaces management functions*/
+static void
+gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
+ GstDDrawSurface * surface);
+
+static GstDDrawSurface *gst_directdrawsink_surface_create (GstDirectDrawSink *
+ ddrawsink, GstCaps * caps, size_t size);
+
+static GstStaticPadTemplate directdrawsink_sink_factory =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-rgb, "
+ "bpp = (int) { 8, 16, 24, 32 }, "
+ "depth = (int) { 0, 8, 16, 24, 32 }, "
+ "endianness = (int) LITTLE_ENDIAN, "
+ "framerate = (fraction) [ 0, MAX ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ]"
+ "; "
+ "video/x-raw-yuv, "
+ "framerate = (fraction) [ 0, MAX ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ], "
+ "format = (fourcc) { YUY2, UYVY, YVU9, YV12, AYUV }")
+ );
+
+enum
+{
+ PROP_0,
+ PROP_SURFACE,
+ PROP_WINDOW,
+ PROP_FULLSCREEN
+};
+
+/* Utility functions */
+static gboolean
+gst_ddrawvideosink_get_format_from_caps (GstCaps * caps,
+ DDPIXELFORMAT * pPixelFormat)
+{
+ GstStructure *structure = NULL;
+ gboolean ret = TRUE;
+
+ /*check params */
+ g_return_val_if_fail (pPixelFormat, FALSE);
+ g_return_val_if_fail (caps, FALSE);
+
+ /*init structure */
+ memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
+ pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
+
+ if (!(structure = gst_caps_get_structure (caps, 0)))
+ return FALSE;
+
+ if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
+ gint depth, bitcount, bitmask;
+
+ pPixelFormat->dwFlags = DDPF_RGB;
+ ret &= gst_structure_get_int (structure, "bpp", &bitcount);
+ pPixelFormat->dwRGBBitCount = bitcount;
+ ret &= gst_structure_get_int (structure, "depth", &depth);
+ ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
+ pPixelFormat->dwRBitMask = bitmask;
+ ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
+ pPixelFormat->dwGBitMask = bitmask;
+ ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
+ pPixelFormat->dwBBitMask = bitmask;
+ } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
+ gint fourcc;
+
+ pPixelFormat->dwFlags = DDPF_FOURCC;
+ ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
+ pPixelFormat->dwFourCC = fourcc;
+ } else {
+ GST_WARNING ("unknown caps name received %" GST_PTR_FORMAT, caps);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static GstCaps *
+gst_ddrawvideosink_get_caps_from_format (DDPIXELFORMAT pixel_format)
+{
+ GstCaps *caps = NULL;
+ gint bpp, depth;
+ guint32 fourcc;
+
+ if ((pixel_format.dwFlags & DDPF_RGB) == DDPF_RGB) {
+ bpp = pixel_format.dwRGBBitCount;
+ if (bpp != 32)
+ depth = bpp;
+ else {
+ if ((pixel_format.dwFlags & DDPF_ALPHAPREMULT) == DDPF_ALPHAPREMULT)
+ depth = 32;
+ else
+ depth = 24;
+ }
+ caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "bpp", G_TYPE_INT, bpp,
+ "depth", G_TYPE_INT, depth,
+ "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
+ }
+
+ if ((pixel_format.dwFlags & DDPF_YUV) == DDPF_YUV) {
+ fourcc = pixel_format.dwFourCC;
+ caps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, fourcc, NULL);
+ }
+
+ g_assert (caps != NULL);
+
+ return caps;
+}
+
+static void
+gst_directdrawsink_center_rect (RECT src, RECT dst, RECT * result)
+{
+ gdouble src_ratio, dst_ratio;
+ long src_width = src.right;
+ long src_height = src.bottom;
+ long dst_width = dst.right - dst.left;
+ long dst_heigth = dst.bottom - dst.top;
+ long result_width = 0, result_height = 0;
+
+ g_return_if_fail (result != NULL);
+
+ src_ratio = (gdouble) src_width / src_height;
+ dst_ratio = (gdouble) dst_width / dst_heigth;
+
+ if (src_ratio > dst_ratio) {
+ /*new height */
+ result_height = (long) (dst_width / src_ratio);
+
+ result->left = dst.left;
+ result->right = dst.right;
+ result->top = dst.top + (dst_heigth - result_height) / 2;
+ result->bottom = result->top + result_height;
+
+ } else if (src_ratio < dst_ratio) {
+ /*new width */
+ result_width = (long) (dst_heigth * src_ratio);
+
+ result->top = dst.top;
+ result->bottom = dst.bottom;
+ result->left = dst.left + (dst_width - result_width) / 2;
+ result->right = result->left + result_width;
+
+ } else {
+ /*same ratio */
+ memcpy (result, &dst, sizeof (RECT));
+ }
+
+ GST_DEBUG ("source is %dx%d dest is %dx%d, result is %dx%d with x,y %dx%d",
+ src_width, src_height, dst_width, dst_heigth, result_width, result_height,
+ result->left, result->right);
+}
+
+/*subclass of GstBuffer which manages surfaces lifetime*/
+static void
+gst_ddrawsurface_finalize (GstDDrawSurface * surface)
+{
+ GstDirectDrawSink *ddrawsink = NULL;
+
+ g_return_if_fail (surface != NULL);
+
+ ddrawsink = surface->ddrawsink;
+ if (!ddrawsink)
+ goto no_sink;
+
+ /* If our geometry changed we can't reuse that image. */
+ if ((surface->width != ddrawsink->video_width) ||
+ (surface->height != ddrawsink->video_height) ||
+ (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
+ sizeof (DDPIXELFORMAT)) != 0)
+ ) {
+ GST_DEBUG ("destroy image as its size changed %dx%d vs current %dx%d",
+ surface->width, surface->height,
+ ddrawsink->video_width, ddrawsink->video_height);
+ gst_directdrawsink_surface_destroy (ddrawsink, surface);
+
+ } else {
+ /* In that case we can reuse the image and add it to our image pool. */
+ GST_DEBUG ("recycling image in pool");
+
+ /* need to increment the refcount again to recycle */
+ gst_buffer_ref (GST_BUFFER (surface));
+
+ g_mutex_lock (ddrawsink->pool_lock);
+ ddrawsink->buffer_pool = g_slist_prepend (ddrawsink->buffer_pool, surface);
+ g_mutex_unlock (ddrawsink->pool_lock);
+ }
+ return;
+
+no_sink:
+ GST_WARNING ("no sink found");
+ return;
+}
+
+static void
+gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
+{
+ surface->surface = NULL;
+ surface->width = 0;
+ surface->height = 0;
+ surface->ddrawsink = NULL;
+ memset (&surface->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
+}
+
+static void
+gst_ddrawsurface_class_init (gpointer g_class, gpointer class_data)
+{
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+ mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+ gst_ddrawsurface_finalize;
+}
+
+GType
+gst_ddrawsurface_get_type (void)
+{
+ static GType _gst_ddrawsurface_type;
+
+ if (G_UNLIKELY (_gst_ddrawsurface_type == 0)) {
+ static const GTypeInfo ddrawsurface_info = {
+ sizeof (GstBufferClass),
+ NULL,
+ NULL,
+ gst_ddrawsurface_class_init,
+ NULL,
+ NULL,
+ sizeof (GstDDrawSurface),
+ 0,
+ (GInstanceInitFunc) gst_ddrawsurface_init,
+ NULL
+ };
+ _gst_ddrawsurface_type = g_type_register_static (GST_TYPE_BUFFER,
+ "GstDDrawSurface", &ddrawsurface_info, 0);
+ }
+ return _gst_ddrawsurface_type;
+}
+
+static GstDirectDrawSink *global_ddrawsink = NULL;
+
+/*GType
+gst_directdrawsink_get_type (void)
+{
+ static GType directdrawsink_type = 0;
+
+ if (!directdrawsink_type) {
+ static const GTypeInfo directdrawsink_info = {
+ sizeof (GstDirectDrawSinkClass),
+ gst_directdrawsink_base_init,
+ NULL,
+ (GClassInitFunc) gst_directdrawsink_class_init,
+ NULL,
+ NULL,
+ sizeof (GstDirectDrawSink),
+ 0,
+ (GInstanceInitFunc) gst_directdrawsink_init,
+ };
+
+ directdrawsink_type =
+ g_type_register_static (GST_TYPE_VIDEO_SINK, "GstDirectDrawSink",
+ &directdrawsink_info, 0);
+ }
+
+ return directdrawsink_type;
+}
+*/
+static void
+gst_directdrawsink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &gst_directdrawsink_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&directdrawsink_sink_factory));
+}
+
+static void
+gst_directdrawsink_class_init (GstDirectDrawSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directdrawsink_finalize);
+
+ gobject_class->get_property =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_get_property);
+ gobject_class->set_property =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_set_property);
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_change_state);
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_get_caps);
+ gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_directdrawsink_set_caps);
+ gstbasesink_class->preroll =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
+ gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_directdrawsink_show_frame);
+
+ gstbasesink_class->get_times =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_get_times);
+ gstbasesink_class->buffer_alloc =
+ GST_DEBUG_FUNCPTR (gst_directdrawsink_buffer_alloc);
+
+ /*install properties */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FULLSCREEN,
+ g_param_spec_boolean ("fullscreen", "fullscreen",
+ "boolean to activate fullscreen", FALSE, G_PARAM_READWRITE));
+
+ /*extern window where we will display the video */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WINDOW,
+ g_param_spec_long ("window", "Window",
+ "The target window for video", G_MINLONG, G_MAXLONG, 0,
+ G_PARAM_WRITABLE));
+
+ /*extern surface where we will blit the video */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SURFACE,
+ g_param_spec_pointer ("surface", "Surface",
+ "The target surface for video", G_PARAM_WRITABLE));
+
+ /*should add a color_key property to permit applications to define the color used for overlays */
+}
+
+static void
+gst_directdrawsink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (object);
+
+ switch (prop_id) {
+ case PROP_SURFACE:
+ ddrawsink->extern_surface = g_value_get_pointer (value);
+ break;
+ case PROP_WINDOW:
+ ddrawsink->video_window = (HWND) g_value_get_long (value);
+ ddrawsink->resize_window = FALSE;
+ break;
+ case PROP_FULLSCREEN:
+ if (g_value_get_boolean (value))
+ ddrawsink->bFullScreen = TRUE;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_directdrawsink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_directdrawsink_finalize (GObject * object)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (object);
+
+ if (ddrawsink->pool_lock) {
+ g_mutex_free (ddrawsink->pool_lock);
+ ddrawsink->pool_lock = NULL;
+ }
+ if (ddrawsink->setup) {
+ gst_directdrawsink_cleanup (ddrawsink);
+ }
+}
+
+static void
+gst_directdrawsink_init (GstDirectDrawSink * ddrawsink,
+ GstDirectDrawSinkClass * g_class)
+{
+ /*init members variables */
+ ddrawsink->ddraw_object = NULL;
+ ddrawsink->primary_surface = NULL;
+ ddrawsink->overlays = NULL;
+ ddrawsink->clipper = NULL;
+ ddrawsink->extern_surface = NULL;
+
+ /*video default values */
+ ddrawsink->video_height = 0;
+ ddrawsink->video_width = 0;
+ ddrawsink->fps_n = 0;
+ ddrawsink->fps_d = 0;
+
+ memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
+
+ ddrawsink->caps = NULL;
+
+ ddrawsink->window_thread = NULL;
+
+ ddrawsink->bUseOverlay = TRUE;
+ ddrawsink->color_key = 0; /*need to be a public property and may be we can enable overlays when this property is set ... */
+
+ ddrawsink->bFullScreen = FALSE;
+ ddrawsink->setup = FALSE;
+
+ ddrawsink->display_modes = NULL;
+ ddrawsink->buffer_pool = NULL;
+
+ ddrawsink->resize_window = TRUE; /*resize only our internal window to the video size */
+ global_ddrawsink = ddrawsink;
+
+ ddrawsink->pool_lock = g_mutex_new ();
+}
+
+static GstCaps *
+gst_directdrawsink_get_caps (GstBaseSink * bsink)
+{
+ GstDirectDrawSink *ddrawsink;
+ GstCaps *caps = NULL;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+
+ if (!ddrawsink->setup) {
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
+ (ddrawsink)));
+
+ GST_DEBUG ("getcaps called and we are not setup yet, "
+ "returning template %" GST_PTR_FORMAT, caps);
+ } else {
+ /*if (ddrawsink->extern_surface) {
+ * We are not rendering to our own surface, returning this surface's
+ * pixel format *
+ GST_WARNING ("using extern surface");
+ caps = gst_ddrawvideosink_get_caps_from_format (ddrawsink->dd_pixel_format);
+ } else */
+
+ /* i think we can't really use the format of the extern surface as the application owning the surface doesn't know
+ the format we will render. But we need to use overlays to overlay any format on the extern surface */
+ caps = gst_caps_ref (ddrawsink->caps);
+ }
+
+ return caps;
+}
+
+static gboolean
+gst_directdrawsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
+{
+ GstDirectDrawSink *ddrawsink;
+ GstStructure *structure = NULL;
+ gboolean ret;
+ const GValue *fps;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!structure)
+ return FALSE;
+
+ ret = gst_structure_get_int (structure, "width", &ddrawsink->video_width);
+ ret &= gst_structure_get_int (structure, "height", &ddrawsink->video_height);
+
+ fps = gst_structure_get_value (structure, "framerate");
+ ret &= (fps != NULL);
+
+ ret &=
+ gst_ddrawvideosink_get_format_from_caps (caps,
+ &ddrawsink->dd_pixel_format);
+
+ if (!ret)
+ return FALSE;
+
+ ddrawsink->fps_n = gst_value_get_fraction_numerator (fps);
+ ddrawsink->fps_d = gst_value_get_fraction_denominator (fps);
+
+ if (ddrawsink->video_window && ddrawsink->resize_window) {
+ SetWindowPos (ddrawsink->video_window, NULL,
+ 0, 0, ddrawsink->video_width + (GetSystemMetrics (SM_CXSIZEFRAME) * 2),
+ ddrawsink->video_height + GetSystemMetrics (SM_CYCAPTION) +
+ (GetSystemMetrics (SM_CYSIZEFRAME) * 2), SWP_SHOWWINDOW | SWP_NOMOVE);
+ }
+
+ /*create overlays flipping chain and an offscreen surface */
+ gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
+
+ return TRUE;
+}
+
+static GstStateChangeReturn
+gst_directdrawsink_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ GST_DEBUG ("GST_STATE_CHANGE_NULL_TO_READY\n");
+
+ if (ddrawsink->video_window == NULL && ddrawsink->extern_surface == NULL)
+ if (!gst_directdrawsink_create_default_window (ddrawsink))
+ return GST_STATE_CHANGE_FAILURE;
+
+ if (!gst_directdrawsink_setup_ddraw (ddrawsink))
+ return GST_STATE_CHANGE_FAILURE;
+
+ if (!(ddrawsink->caps = gst_directdrawsink_get_ddrawcaps (ddrawsink)))
+ return GST_STATE_CHANGE_FAILURE;
+
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_DEBUG ("GST_STATE_CHANGE_READY_TO_PAUSED\n");
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ GST_DEBUG ("GST_STATE_CHANGE_PAUSED_TO_PLAYING\n");
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ GST_DEBUG ("GST_STATE_CHANGE_PLAYING_TO_PAUSED\n");
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_DEBUG ("GST_STATE_CHANGE_PAUSED_TO_READY\n");
+
+ ddrawsink->fps_n = 0;
+ ddrawsink->fps_d = 1;
+ ddrawsink->video_width = 0;
+ ddrawsink->video_height = 0;
+
+ if (ddrawsink->buffer_pool)
+ gst_directdrawsink_bufferpool_clear (ddrawsink);
+
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ GST_DEBUG ("GST_STATE_CHANGE_READY_TO_NULL\n");
+
+ if (ddrawsink->setup)
+ gst_directdrawsink_cleanup (ddrawsink);
+
+ break;
+ }
+
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+}
+
+/**
+ * Get DirectDraw error message.
+ * @hr: HRESULT code
+ * Returns: Text representation of the error.
+ */
+char *
+DDErrorString (HRESULT hr)
+{
+ switch (hr) {
+ case DDERR_ALREADYINITIALIZED:
+ return "DDERR_ALREADYINITIALIZED";
+ case DDERR_CANNOTATTACHSURFACE:
+ return "DDERR_CANNOTATTACHSURFACE";
+ case DDERR_CANNOTDETACHSURFACE:
+ return "DDERR_CANNOTDETACHSURFACE";
+ case DDERR_CURRENTLYNOTAVAIL:
+ return "DDERR_CURRENTLYNOTAVAIL";
+ case DDERR_EXCEPTION:
+ return "DDERR_EXCEPTION";
+ case DDERR_GENERIC:
+ return "DDERR_GENERIC";
+ case DDERR_HEIGHTALIGN:
+ return "DDERR_HEIGHTALIGN";
+ case DDERR_INCOMPATIBLEPRIMARY:
+ return "DDERR_INCOMPATIBLEPRIMARY";
+ case DDERR_INVALIDCAPS:
+ return "DDERR_INVALIDCAPS";
+ case DDERR_INVALIDCLIPLIST:
+ return "DDERR_INVALIDCLIPLIST";
+ case DDERR_INVALIDMODE:
+ return "DDERR_INVALIDMODE";
+ case DDERR_INVALIDOBJECT:
+ return "DDERR_INVALIDOBJECT";
+ case DDERR_INVALIDPARAMS:
+ return "DDERR_INVALIDPARAMS";
+ case DDERR_INVALIDPIXELFORMAT:
+ return "DDERR_INVALIDPIXELFORMAT";
+ case DDERR_INVALIDRECT:
+ return "DDERR_INVALIDRECT";
+ case DDERR_LOCKEDSURFACES:
+ return "DDERR_LOCKEDSURFACES";
+ case DDERR_NO3D:
+ return "DDERR_NO3D";
+ case DDERR_NOALPHAHW:
+ return "DDERR_NOALPHAHW";
+ case DDERR_NOCLIPLIST:
+ return "DDERR_NOCLIPLIST";
+ case DDERR_NOCOLORCONVHW:
+ return "DDERR_NOCOLORCONVHW";
+ case DDERR_NOCOOPERATIVELEVELSET:
+ return "DDERR_NOCOOPERATIVELEVELSET";
+ case DDERR_NOCOLORKEY:
+ return "DDERR_NOCOLORKEY";
+ case DDERR_NOCOLORKEYHW:
+ return "DDERR_NOCOLORKEYHW";
+ case DDERR_NODIRECTDRAWSUPPORT:
+ return "DDERR_NODIRECTDRAWSUPPORT";
+ case DDERR_NOEXCLUSIVEMODE:
+ return "DDERR_NOEXCLUSIVEMODE";
+ case DDERR_NOFLIPHW:
+ return "DDERR_NOFLIPHW";
+ case DDERR_NOGDI:
+ return "DDERR_NOGDI";
+ case DDERR_NOMIRRORHW:
+ return "DDERR_NOMIRRORHW";
+ case DDERR_NOTFOUND:
+ return "DDERR_NOTFOUND";
+ case DDERR_NOOVERLAYHW:
+ return "DDERR_NOOVERLAYHW";
+ case DDERR_NORASTEROPHW:
+ return "DDERR_NORASTEROPHW";
+ case DDERR_NOROTATIONHW:
+ return "DDERR_NOROTATIONHW";
+ case DDERR_NOSTRETCHHW:
+ return "DDERR_NOSTRETCHHW";
+ case DDERR_NOT4BITCOLOR:
+ return "DDERR_NOT4BITCOLOR";
+ case DDERR_NOT4BITCOLORINDEX:
+ return "DDERR_NOT4BITCOLORINDEX";
+ case DDERR_NOT8BITCOLOR:
+ return "DDERR_NOT8BITCOLOR";
+ case DDERR_NOTEXTUREHW:
+ return "DDERR_NOTEXTUREHW";
+ case DDERR_NOVSYNCHW:
+ return "DDERR_NOVSYNCHW";
+ case DDERR_NOZBUFFERHW:
+ return "DDERR_NOZBUFFERHW";
+ case DDERR_NOZOVERLAYHW:
+ return "DDERR_NOZOVERLAYHW";
+ case DDERR_OUTOFCAPS:
+ return "DDERR_OUTOFCAPS";
+ case DDERR_OUTOFMEMORY:
+ return "DDERR_OUTOFMEMORY";
+ case DDERR_OUTOFVIDEOMEMORY:
+ return "DDERR_OUTOFVIDEOMEMORY";
+ case DDERR_OVERLAYCANTCLIP:
+ return "DDERR_OVERLAYCANTCLIP";
+ case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
+ return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
+ case DDERR_PALETTEBUSY:
+ return "DDERR_PALETTEBUSY";
+ case DDERR_COLORKEYNOTSET:
+ return "DDERR_COLORKEYNOTSET";
+ case DDERR_SURFACEALREADYATTACHED:
+ return "DDERR_SURFACEALREADYATTACHED";
+ case DDERR_SURFACEALREADYDEPENDENT:
+ return "DDERR_SURFACEALREADYDEPENDENT";
+ case DDERR_SURFACEBUSY:
+ return "DDERR_SURFACEBUSY";
+ case DDERR_CANTLOCKSURFACE:
+ return "DDERR_CANTLOCKSURFACE";
+ case DDERR_SURFACEISOBSCURED:
+ return "DDERR_SURFACEISOBSCURED";
+ case DDERR_SURFACELOST:
+ return "DDERR_SURFACELOST";
+ case DDERR_SURFACENOTATTACHED:
+ return "DDERR_SURFACENOTATTACHED";
+ case DDERR_TOOBIGHEIGHT:
+ return "DDERR_TOOBIGHEIGHT";
+ case DDERR_TOOBIGSIZE:
+ return "DDERR_TOOBIGSIZE";
+ case DDERR_TOOBIGWIDTH:
+ return "DDERR_TOOBIGWIDTH";
+ case DDERR_UNSUPPORTED:
+ return "DDERR_UNSUPPORTED";
+ case DDERR_UNSUPPORTEDFORMAT:
+ return "DDERR_UNSUPPORTEDFORMAT";
+ case DDERR_UNSUPPORTEDMASK:
+ return "DDERR_UNSUPPORTEDMASK";
+ case DDERR_VERTICALBLANKINPROGRESS:
+ return "DDERR_VERTICALBLANKINPROGRESS";
+ case DDERR_WASSTILLDRAWING:
+ return "DDERR_WASSTILLDRAWING";
+ case DDERR_XALIGN:
+ return "DDERR_XALIGN";
+ case DDERR_INVALIDDIRECTDRAWGUID:
+ return "DDERR_INVALIDDIRECTDRAWGUID";
+ case DDERR_DIRECTDRAWALREADYCREATED:
+ return "DDERR_DIRECTDRAWALREADYCREATED";
+ case DDERR_NODIRECTDRAWHW:
+ return "DDERR_NODIRECTDRAWHW";
+ case DDERR_PRIMARYSURFACEALREADYEXISTS:
+ return "DDERR_PRIMARYSURFACEALREADYEXISTS";
+ case DDERR_NOEMULATION:
+ return "DDERR_NOEMULATION";
+ case DDERR_REGIONTOOSMALL:
+ return "DDERR_REGIONTOOSMALL";
+ case DDERR_CLIPPERISUSINGHWND:
+ return "DDERR_CLIPPERISUSINGHWND";
+ case DDERR_NOCLIPPERATTACHED:
+ return "DDERR_NOCLIPPERATTACHED";
+ case DDERR_NOHWND:
+ return "DDERR_NOHWND";
+ case DDERR_HWNDSUBCLASSED:
+ return "DDERR_HWNDSUBCLASSED";
+ case DDERR_HWNDALREADYSET:
+ return "DDERR_HWNDALREADYSET";
+ case DDERR_NOPALETTEATTACHED:
+ return "DDERR_NOPALETTEATTACHED";
+ case DDERR_NOPALETTEHW:
+ return "DDERR_NOPALETTEHW";
+ case DDERR_BLTFASTCANTCLIP:
+ return "DDERR_BLTFASTCANTCLIP";
+ case DDERR_NOBLTHW:
+ return "DDERR_NOBLTHW";
+ case DDERR_NODDROPSHW:
+ return "DDERR_NODDROPSHW";
+ case DDERR_OVERLAYNOTVISIBLE:
+ return "DDERR_OVERLAYNOTVISIBLE";
+ case DDERR_NOOVERLAYDEST:
+ return "DDERR_NOOVERLAYDEST";
+ case DDERR_INVALIDPOSITION:
+ return "DDERR_INVALIDPOSITION";
+ case DDERR_NOTAOVERLAYSURFACE:
+ return "DDERR_NOTAOVERLAYSURFACE";
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ return "DDERR_EXCLUSIVEMODEALREADYSET";
+ case DDERR_NOTFLIPPABLE:
+ return "DDERR_NOTFLIPPABLE";
+ case DDERR_CANTDUPLICATE:
+ return "DDERR_CANTDUPLICATE";
+ case DDERR_NOTLOCKED:
+ return "DDERR_NOTLOCKED";
+ case DDERR_CANTCREATEDC:
+ return "DDERR_CANTCREATEDC";
+ case DDERR_NODC:
+ return "DDERR_NODC";
+ case DDERR_WRONGMODE:
+ return "DDERR_WRONGMODE";
+ case DDERR_IMPLICITLYCREATED:
+ return "DDERR_IMPLICITLYCREATED";
+ case DDERR_NOTPALETTIZED:
+ return "DDERR_NOTPALETTIZED";
+ case DDERR_UNSUPPORTEDMODE:
+ return "DDERR_UNSUPPORTEDMODE";
+ case DDERR_NOMIPMAPHW:
+ return "DDERR_NOMIPMAPHW";
+ case DDERR_INVALIDSURFACETYPE:
+ return "DDERR_INVALIDSURFACETYPE";
+ case DDERR_DCALREADYCREATED:
+ return "DDERR_DCALREADYCREATED";
+ case DDERR_CANTPAGELOCK:
+ return "DDERR_CANTPAGELOCK";
+ case DDERR_CANTPAGEUNLOCK:
+ return "DDERR_CANTPAGEUNLOCK";
+ case DDERR_NOTPAGELOCKED:
+ return "DDERR_NOTPAGELOCKED";
+ case DDERR_NOTINITIALIZED:
+ return "DDERR_NOTINITIALIZED";
+ }
+ return "Unknown Error";
+}
+
+
+static gint gtempcpt = 0;
+static GstFlowReturn
+gst_directdrawsink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
+ guint size, GstCaps * caps, GstBuffer ** buf)
+{
+ GstDirectDrawSink *ddrawsink = NULL;
+ GstDDrawSurface *surface = NULL;
+ GstStructure *structure = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+ GST_DEBUG ("a buffer of %d bytes was requested", size);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ g_mutex_lock (ddrawsink->pool_lock);
+
+ /* Inspect our buffer pool */
+ while (ddrawsink->buffer_pool) {
+ surface = (GstDDrawSurface *) ddrawsink->buffer_pool->data;
+
+ if (surface) {
+ /* Removing from the pool */
+ ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
+ ddrawsink->buffer_pool);
+
+ /* If the surface is invalid for our need, destroy */
+ if ((surface->width != ddrawsink->video_width) ||
+ (surface->height != ddrawsink->video_height) ||
+ (memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
+ sizeof (DDPIXELFORMAT)))
+ ) {
+ gst_directdrawsink_surface_destroy (ddrawsink, surface);
+ surface = NULL;
+ } else {
+ /* We found a suitable surface */
+ break;
+ }
+ }
+ }
+
+ /* We haven't found anything, creating a new one */
+ if (!surface) {
+ surface = gst_directdrawsink_surface_create (ddrawsink, caps, size);
+ gtempcpt++;
+ }
+
+ /* Now we should have a surface, set appropriate caps on it */
+ if (surface) {
+ gst_buffer_set_caps (GST_BUFFER (surface), caps);
+ }
+
+ g_mutex_unlock (ddrawsink->pool_lock);
+
+ *buf = GST_BUFFER (surface);
+
+ return ret;
+}
+
+static gboolean
+gst_directdrawsink_fill_colorkey (LPDIRECTDRAWSURFACE surface, DWORD dwColorKey)
+{
+ DDBLTFX ddbfx;
+
+ if (!surface)
+ return FALSE;
+
+ ddbfx.dwSize = sizeof (DDBLTFX);
+ ddbfx.dwFillColor = dwColorKey;
+
+ if (IDirectDrawSurface_Blt (surface,
+ NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx) == DD_OK)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+static void
+gst_directdrawsink_show_overlay (GstDirectDrawSink * ddrawsink)
+{
+ HRESULT hRes;
+ RECT destsurf_rect, src_rect;
+ POINT dest_surf_point;
+ DDOVERLAYFX ddofx;
+ LPDIRECTDRAWSURFACE surface = NULL;
+
+ if (!ddrawsink || !ddrawsink->overlays)
+ return;
+
+ if (ddrawsink->extern_surface)
+ surface = ddrawsink->extern_surface;
+ else
+ surface = ddrawsink->primary_surface;
+
+ if (ddrawsink->extern_surface) {
+ destsurf_rect.left = 0;
+ destsurf_rect.top = 0;
+ destsurf_rect.right = ddrawsink->out_width;
+ destsurf_rect.bottom = ddrawsink->out_height;
+ } else {
+ dest_surf_point.x = 0;
+ dest_surf_point.y = 0;
+ ClientToScreen (ddrawsink->video_window, &dest_surf_point);
+ GetClientRect (ddrawsink->video_window, &destsurf_rect);
+ OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
+ }
+
+ src_rect.top = 0;
+ src_rect.left = 0;
+ src_rect.bottom = ddrawsink->video_height;
+ src_rect.right = ddrawsink->video_width;
+ gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
+
+ gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
+
+ ddofx.dwSize = sizeof (DDOVERLAYFX);
+ ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
+ ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
+
+ hRes = IDirectDrawSurface_UpdateOverlay (ddrawsink->overlays,
+ NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
+ &ddofx);
+}
+
+static GstFlowReturn
+gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
+{
+ GstDirectDrawSink *ddrawsink;
+ HRESULT hRes;
+
+ DDSURFACEDESC surf_desc;
+ RECT destsurf_rect, src_rect;
+ POINT dest_surf_point;
+ LPDIRECTDRAWSURFACE lpSurface = NULL;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+
+ if (ddrawsink->extern_surface) {
+ destsurf_rect.left = 0;
+ destsurf_rect.top = 0;
+ destsurf_rect.right = ddrawsink->out_width;
+ destsurf_rect.bottom = ddrawsink->out_height;
+ } else {
+ dest_surf_point.x = 0;
+ dest_surf_point.y = 0;
+ ClientToScreen (ddrawsink->video_window, &dest_surf_point);
+ GetClientRect (ddrawsink->video_window, &destsurf_rect);
+ OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y);
+ }
+
+ src_rect.top = 0;
+ src_rect.left = 0;
+ src_rect.bottom = ddrawsink->video_height;
+ src_rect.right = ddrawsink->video_width;
+ gst_directdrawsink_center_rect (src_rect, destsurf_rect, &destsurf_rect);
+
+ if (ddrawsink->bUseOverlay) {
+ /*get the back buffer of the overlays flipping chain */
+ DDSCAPS ddbackcaps;
+
+ ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
+ IDirectDrawSurface_GetAttachedSurface (ddrawsink->overlays, &ddbackcaps,
+ &lpSurface);
+ } else {
+ /*use our offscreen surface */
+ lpSurface = ddrawsink->offscreen_surface;
+ }
+
+ if (lpSurface == NULL)
+ return GST_FLOW_ERROR;
+
+ if (!GST_IS_DDRAWSURFACE (buf) ||
+ ((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
+
+ LPBYTE data = NULL;
+ guint src_pitch, line;
+
+ /* Check for lost surface */
+ if (IDirectDrawSurface_IsLost (lpSurface) == DDERR_SURFACELOST) {
+ IDirectDrawSurface_Restore (lpSurface);
+ }
+
+ ZeroMemory (&surf_desc, sizeof (surf_desc));
+ surf_desc.dwSize = sizeof (surf_desc);
+
+ /* Lock the surface */
+ hRes =
+ IDirectDrawSurface_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
+ NULL);
+ if (hRes != DD_OK) {
+ GST_DEBUG ("gst_directdrawsink_show_frame failed locking surface %s",
+ DDErrorString (hRes));
+ return GST_FLOW_ERROR;
+ }
+
+ /* Write data */
+ data = surf_desc.lpSurface;
+
+ /* Source video rowbytes */
+ src_pitch = GST_BUFFER_SIZE (buf) / ddrawsink->video_height;
+
+ /* Write each line respecting dest surface pitch */
+ for (line = 0; line < surf_desc.dwHeight; line++) {
+ memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch);
+ data += surf_desc.lPitch;
+ }
+
+ /* Unlock the surface */
+ hRes = IDirectDrawSurface_Unlock (lpSurface, NULL);
+ if (hRes != DD_OK) {
+ GST_DEBUG ("gst_directdrawsink_show_frame failed unlocking surface %s",
+ DDErrorString (hRes));
+ return GST_FLOW_ERROR;
+ }
+
+ if (ddrawsink->bUseOverlay) {
+ /*Flip to front overlay */
+ hRes =
+ IDirectDrawSurface_Flip (ddrawsink->overlays, lpSurface, DDFLIP_WAIT);
+ IDirectDrawSurface_Release (lpSurface);
+ lpSurface = NULL;
+ } else {
+ if (ddrawsink->extern_surface) {
+ if (ddrawsink->out_height == ddrawsink->video_height &&
+ ddrawsink->out_width == ddrawsink->video_width) {
+ /*Fast blit to extern surface */
+ hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
+ lpSurface, NULL, DDBLTFAST_WAIT);
+
+ } else {
+ /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
+ hRes =
+ IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
+ lpSurface, NULL, DDBLT_WAIT, NULL);
+ }
+ } else {
+ /*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
+ hRes =
+ IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
+ lpSurface, NULL, DDBLT_WAIT, NULL);
+ }
+ }
+ } else {
+
+ GstDDrawSurface *surface = NULL;
+
+ surface = GST_DDRAWSURFACE (buf);
+
+ /* Unlocking surface before blit */
+ IDirectDrawSurface_Unlock (surface->surface, NULL);
+ surface->locked = FALSE;
+
+ /* Check for lost surfaces */
+ if (IDirectDrawSurface_IsLost (surface->surface) == DDERR_SURFACELOST) {
+ IDirectDrawSurface_Restore (surface->surface);
+ }
+
+ if (ddrawsink->bUseOverlay) {
+ /* blit to the overlays back buffer */
+ hRes = IDirectDrawSurface_Blt (lpSurface, NULL,
+ surface->surface, NULL, DDBLT_WAIT, NULL);
+
+ hRes = IDirectDrawSurface_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
+ if (hRes != DD_OK)
+ GST_WARNING ("error flipping");
+
+ } else {
+ if (ddrawsink->extern_surface) {
+ /*blit to the extern surface */
+ if (ddrawsink->out_height == ddrawsink->video_height &&
+ ddrawsink->out_width == ddrawsink->video_width) {
+ /*Fast blit to extern surface */
+ hRes = IDirectDrawSurface_BltFast (ddrawsink->extern_surface, 0, 0,
+ surface->surface, NULL, DDBLTFAST_WAIT);
+
+ } else {
+ /*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
+ hRes =
+ IDirectDrawSurface_Blt (ddrawsink->extern_surface, &destsurf_rect,
+ surface->surface, NULL, DDBLT_WAIT, NULL);
+ }
+ } else {
+ /*blit to our primary surface */
+ hRes =
+ IDirectDrawSurface_Blt (ddrawsink->primary_surface, &destsurf_rect,
+ surface->surface, NULL, DDBLT_WAIT, NULL);
+ if (hRes != DD_OK)
+ GST_WARNING ("IDirectDrawSurface_Blt returned %s",
+ DDErrorString (hRes));
+ }
+ }
+ }
+
+ if (ddrawsink->bUseOverlay)
+ gst_directdrawsink_show_overlay (ddrawsink);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_directdrawsink_setup_ddraw (GstDirectDrawSink * ddrawsink)
+{
+ gboolean bRet = TRUE;
+ HRESULT hRes;
+ DWORD dwCooperativeLevel;
+ DDSURFACEDESC dd_surface_desc;
+
+ /*create an instance of the ddraw object */
+ hRes = DirectDrawCreate (NULL, &ddrawsink->ddraw_object, NULL);
+ if (hRes != DD_OK || ddrawsink->ddraw_object == NULL)
+ return FALSE;
+
+ /*set cooperative level */
+ if (ddrawsink->bFullScreen)
+ dwCooperativeLevel = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
+ else
+ dwCooperativeLevel = DDSCL_NORMAL;
+
+ hRes = IDirectDraw_SetCooperativeLevel (ddrawsink->ddraw_object,
+ ddrawsink->video_window, dwCooperativeLevel);
+ if (hRes != DD_OK)
+ bRet = FALSE;
+
+ /*for fullscreen mode, setup display mode */
+ if (ddrawsink->bFullScreen) {
+ hRes = IDirectDraw_SetDisplayMode (ddrawsink->ddraw_object, 640, 480, 32);
+ }
+
+ if (!ddrawsink->extern_surface) {
+ /*create our primary surface */
+ memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
+ dd_surface_desc.dwSize = sizeof (dd_surface_desc);
+ dd_surface_desc.dwFlags = DDSD_CAPS;
+ dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
+ &ddrawsink->primary_surface, NULL);
+ if (hRes != DD_OK)
+ bRet = FALSE;
+
+ if (bRet == FALSE) {
+ if (ddrawsink->ddraw_object) {
+ IDirectDraw_Release (ddrawsink->ddraw_object);
+ GST_DEBUG ("CreateSurface failed with: %s", DDErrorString (hRes));
+ return FALSE;
+ }
+ }
+
+ hRes = IDirectDraw_CreateClipper (ddrawsink->ddraw_object, 0,
+ &ddrawsink->clipper, NULL);
+ if (hRes == DD_OK) {
+ hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
+ ddrawsink->video_window);
+ hRes = IDirectDrawSurface_SetClipper (ddrawsink->primary_surface,
+ ddrawsink->clipper);
+ }
+ } else {
+ DDSURFACEDESC desc_surface;
+
+ desc_surface.dwSize = sizeof (DDSURFACEDESC);
+
+ /*get extern surface size */
+ hRes = IDirectDrawSurface_GetSurfaceDesc (ddrawsink->extern_surface,
+ &desc_surface);
+ if (hRes != DD_OK) {
+ /*error while retrieving ext surface description */
+ return FALSE;
+ }
+
+ ddrawsink->out_width = desc_surface.dwWidth;
+ ddrawsink->out_height = desc_surface.dwHeight;
+
+ /*get extern surface pixel format (FIXME not needed if we are using overlays) */
+ ddrawsink->dd_pixel_format.dwSize = sizeof (DDPIXELFORMAT);
+ hRes = IDirectDrawSurface_GetPixelFormat (ddrawsink->extern_surface,
+ &ddrawsink->dd_pixel_format);
+ if (hRes != DD_OK) {
+ /*error while retrieving ext surface pixel format */
+ return FALSE;
+ }
+
+ /*get specific caps if needed ... */
+ }
+
+ ddrawsink->setup = TRUE;
+
+ return bRet;
+}
+
+long FAR PASCAL
+WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_ERASEBKGND:
+ return TRUE;
+/* case WM_WINDOWPOSCHANGED:
+ case WM_MOVE:
+ case WM_SIZE:
+ if(global_ddrawsink && global_ddrawsink->bUseOverlay)
+ gst_directdrawsink_show_overlay(global_ddrawsink);
+ break;
+ case WM_PAINT:
+ if(global_ddrawsink && global_ddrawsink->bUseOverlay)
+ {
+ if(global_ddrawsink->extern_surface)
+ gst_directdrawsink_fill_colorkey(global_ddrawsink->extern_surface,
+ global_ddrawsink->color_key);
+ else
+ gst_directdrawsink_fill_colorkey(global_ddrawsink->primary_surface,
+ global_ddrawsink->color_key);
+ }
+ break;
+*/
+ case WM_DESTROY:
+ PostQuitMessage (0);
+ break;
+ case WM_CLOSE:
+ DestroyWindow (hWnd);
+ return 0;
+ }
+ return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+static gpointer
+gst_directdrawsink_window_thread (GstDirectDrawSink * ddrawsink)
+{
+ WNDCLASS WndClass;
+
+ memset (&WndClass, 0, sizeof (WNDCLASS));
+
+ WndClass.style = CS_HREDRAW | CS_VREDRAW;
+ WndClass.hInstance = GetModuleHandle (NULL);
+ WndClass.lpszClassName = "GStreamer-DirectDraw";
+ WndClass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = 0;
+ WndClass.lpfnWndProc = WndProc;
+ WndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
+
+ RegisterClass (&WndClass);
+
+ ddrawsink->video_window = CreateWindowEx (0, "GStreamer-DirectDraw",
+ "GStreamer-DirectDraw sink default window",
+ WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 0, 0, 640, 480, NULL, NULL,
+ WndClass.hInstance, NULL);
+
+ if (ddrawsink->video_window == NULL)
+ return FALSE;
+
+ ShowWindow (ddrawsink->video_window, SW_SHOW);
+
+ /*start message loop processing our default window messages */
+ while (1) {
+ MSG msg;
+
+ if (!GetMessage (&msg, ddrawsink->video_window, 0, 0))
+ break;
+ DispatchMessage (&msg);
+ }
+
+ return NULL;
+}
+
+static gboolean
+gst_directdrawsink_create_default_window (GstDirectDrawSink * ddrawsink)
+{
+ ddrawsink->window_thread = g_thread_create (
+ (GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
+
+ if (ddrawsink->window_thread == NULL)
+ return FALSE;
+
+ /*TODO:wait for the window to be created with timeout */
+
+ return TRUE;
+}
+
+static gboolean
+gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
+{
+ DDSURFACEDESC dd_surface_desc;
+ HRESULT hRes;
+
+ memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
+ dd_surface_desc.dwSize = sizeof (dd_surface_desc);
+
+ dd_surface_desc.dwFlags =
+ DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+ dd_surface_desc.dwHeight = ddrawsink->video_height;
+ dd_surface_desc.dwWidth = ddrawsink->video_width;
+ memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
+ sizeof (DDPIXELFORMAT));
+
+ if (ddrawsink->bUseOverlay) {
+ /*create overlays flipping chain */
+ dd_surface_desc.ddsCaps.dwCaps =
+ DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ dd_surface_desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
+ dd_surface_desc.dwBackBufferCount = 1;
+
+ hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
+ &ddrawsink->overlays, NULL);
+
+ if (hRes != DD_OK) {
+ GST_DEBUG ("create_ddraw_surfaces:CreateSurface(overlays) failed %s",
+ DDErrorString (hRes));
+ return FALSE;
+ }
+ } else {
+ dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+
+ hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
+ &ddrawsink->offscreen_surface, NULL);
+
+ if (hRes != DD_OK) {
+ GST_DEBUG ("create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
+ DDErrorString (hRes));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gst_directdrawsink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+ GstClockTime * start, GstClockTime * end)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ *start = GST_BUFFER_TIMESTAMP (buf);
+ if (GST_BUFFER_DURATION_IS_VALID (buf)) {
+ *end = *start + GST_BUFFER_DURATION (buf);
+ } else {
+ if (ddrawsink->fps_n > 0) {
+ *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
+ }
+ }
+ }
+}
+
+static int
+gst_directdrawsink_get_depth (LPDDPIXELFORMAT lpddpfPixelFormat)
+{
+ gint order = 0, binary;
+
+ binary =
+ lpddpfPixelFormat->dwRBitMask | lpddpfPixelFormat->
+ dwGBitMask | lpddpfPixelFormat->dwBBitMask | lpddpfPixelFormat->
+ dwRGBAlphaBitMask;
+ while (binary != 0) {
+ if ((binary % 2) == 1)
+ order++;
+ binary = binary >> 1;
+ }
+ return order;
+}
+
+HRESULT WINAPI
+EnumModesCallback2 (LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext)
+{
+ GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
+ GstCaps *format_caps = NULL;
+
+ if (!ddrawsink || !lpDDSurfaceDesc)
+ return DDENUMRET_CANCEL;
+
+ if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
+ GST_DEBUG ("Display mode found with DDSD_PIXELFORMAT not set");
+ return DDENUMRET_OK;
+ }
+
+ if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
+ return DDENUMRET_OK;
+
+ format_caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
+ "bpp", G_TYPE_INT, lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
+ "depth", G_TYPE_INT,
+ gst_directdrawsink_get_depth (&lpDDSurfaceDesc->ddpfPixelFormat),
+ "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "red_mask", G_TYPE_INT,
+ lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask, "green_mask", G_TYPE_INT,
+ lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask, "blue_mask", G_TYPE_INT,
+ lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask, NULL);
+
+ if (format_caps) {
+ gst_caps_append (ddrawsink->caps, format_caps);
+ }
+
+ return DDENUMRET_OK;
+}
+
+static GstCaps *
+gst_directdrawsink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
+{
+ HRESULT hRes = S_OK;
+ DWORD dwFourccCodeIndex = 0;
+ LPDWORD pdwFourccCodes = NULL;
+ DWORD dwNbFourccCodes = 0;
+ GstCaps *format_caps = NULL;
+
+ ddrawsink->caps = gst_caps_new_empty ();
+ if (!ddrawsink->caps)
+ return FALSE;
+
+ /*enumerate display modes exposed by directdraw object */
+ hRes =
+ IDirectDraw_EnumDisplayModes (ddrawsink->ddraw_object, DDEDM_REFRESHRATES,
+ NULL, ddrawsink, EnumModesCallback2);
+ if (hRes != DD_OK) {
+ GST_DEBUG ("EnumDisplayModes returns: %s", DDErrorString (hRes));
+ return FALSE;
+ }
+
+ /* enumerate non-rgb modes exposed by directdraw object */
+ IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object, &dwNbFourccCodes, NULL);
+ if (dwNbFourccCodes != 0) {
+ pdwFourccCodes = g_new0 (DWORD, dwNbFourccCodes);
+ if (!pdwFourccCodes)
+ return FALSE;
+
+ if (FAILED (IDirectDraw_GetFourCCCodes (ddrawsink->ddraw_object,
+ &dwNbFourccCodes, pdwFourccCodes))) {
+ g_free (pdwFourccCodes);
+ return FALSE;
+ }
+
+ for (dwFourccCodeIndex = 0; dwFourccCodeIndex < dwNbFourccCodes;
+ dwFourccCodeIndex++) {
+ /*support only yuv formats YUY2, UYVY, YVU9, YV12, AYUV */
+ if (pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'U', 'Y', '2')
+ || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('U', 'Y', 'V',
+ 'Y')
+ || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', 'U',
+ '9')
+ || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('Y', 'V', '1',
+ '2')
+ || pdwFourccCodes[dwFourccCodeIndex] == mmioFOURCC ('A', 'Y', 'U',
+ 'V')
+ ) {
+ format_caps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, pdwFourccCodes[dwFourccCodeIndex],
+ "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+
+ if (format_caps)
+ gst_caps_append (ddrawsink->caps, format_caps);
+ }
+ }
+
+ g_free (pdwFourccCodes);
+ }
+
+ if (gst_caps_is_empty (ddrawsink->caps)) {
+ gst_caps_unref (ddrawsink->caps);
+
+ GST_ELEMENT_ERROR (ddrawsink, STREAM, WRONG_TYPE, (NULL),
+ ("No supported format found"));
+ return NULL;
+ }
+
+ return ddrawsink->caps;
+}
+
+/* Creates miniobject and our internal surface */
+static GstDDrawSurface *
+gst_directdrawsink_surface_create (GstDirectDrawSink * ddrawsink,
+ GstCaps * caps, size_t size)
+{
+ GstDDrawSurface *surface = NULL;
+ GstStructure *structure = NULL;
+
+ HRESULT hRes;
+ DDSURFACEDESC surf_desc, surf_lock_desc;
+
+ g_return_val_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink), NULL);
+
+ /*init structures */
+ memset (&surf_desc, 0, sizeof (surf_desc));
+ memset (&surf_lock_desc, 0, sizeof (surf_desc));
+ surf_desc.dwSize = sizeof (surf_desc);
+ surf_lock_desc.dwSize = sizeof (surf_lock_desc);
+
+ /*create miniobject and initialize it */
+ surface = (GstDDrawSurface *) gst_mini_object_new (GST_TYPE_DDRAWSURFACE);
+ surface->locked = FALSE;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "width", &surface->width) ||
+ !gst_structure_get_int (structure, "height", &surface->height)) {
+ GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
+ }
+
+ if (!gst_ddrawvideosink_get_format_from_caps (caps,
+ &surface->dd_pixel_format)) {
+ GST_WARNING ("failed getting pixel format from caps %" GST_PTR_FORMAT,
+ caps);
+ }
+
+ if (ddrawsink->ddraw_object) {
+ /* Creating an internal surface which will be used as GstBuffer, we used
+ the detected pixel format and video dimensions */
+ gint pitch = GST_ROUND_UP_8 (size / surface->height);
+
+ surf_desc.lPitch = pitch;
+
+ surf_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ surf_desc.dwFlags =
+ DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH;
+ surf_desc.dwHeight = surface->height;
+ surf_desc.dwWidth = surface->width;
+
+ memcpy (&(surf_desc.ddpfPixelFormat), &surface->dd_pixel_format,
+ sizeof (DDPIXELFORMAT));
+
+ hRes = IDirectDraw_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
+ &surface->surface, NULL);
+ if (hRes != DD_OK) {
+ gst_object_unref (surface);
+ surface = NULL;
+ goto beach;
+ }
+
+ /* Locking the surface to acquire the memory pointer.
+ Use DDLOCK_NOSYSLOCK to disable syslock which can cause a deadlock
+ if directdraw api is used while a buffer is lock */
+ hRes = IDirectDrawSurface_Lock (surface->surface, NULL, &surf_lock_desc,
+ DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
+ surface->locked = TRUE;
+
+ if (surf_lock_desc.lPitch != pitch) {
+ GST_DEBUG
+ ("DDraw stride/pitch %d isn't as expected value %d, let's continue allocating buffer.",
+ surf_lock_desc.lPitch, pitch);
+ IDirectDrawSurface_Release (surface->surface);
+ goto surface_pitch_bad;
+ }
+
+ GST_DEBUG ("allocating a surface of %d bytes (stride=%d)\n", size,
+ surf_lock_desc.lPitch);
+ GST_BUFFER_DATA (surface) = surf_lock_desc.lpSurface;
+ GST_BUFFER_SIZE (surface) = surf_lock_desc.lPitch * surface->height;
+ } else {
+
+ surface_pitch_bad:
+ GST_BUFFER (surface)->malloc_data = g_malloc (size);
+ GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data;
+ GST_BUFFER_SIZE (surface) = size;
+ surface->surface = NULL;
+ printf ("allocating a buffer of %d bytes\n", size);
+ }
+
+ /* Keep a ref to our sink */
+ surface->ddrawsink = gst_object_ref (ddrawsink);
+
+beach:
+ return surface;
+}
+
+/* We are called from the finalize method of miniobject, the object will be
+ * destroyed so we just have to clean our internal stuff */
+static void
+gst_directdrawsink_surface_destroy (GstDirectDrawSink * ddrawsink,
+ GstDDrawSurface * surface)
+{
+ g_return_if_fail (GST_IS_DIRECTDRAW_SINK (ddrawsink));
+
+ /* Release our internal surface */
+ if (surface->surface) {
+ if (surface->locked) {
+ IDirectDrawSurface_Unlock (surface->surface, NULL);
+ surface->locked = FALSE;
+ }
+ IDirectDrawSurface_Release (surface->surface);
+ surface->surface = NULL;
+ }
+
+ if (GST_BUFFER (surface)->malloc_data) {
+ g_free (GST_BUFFER (surface)->malloc_data);
+ GST_BUFFER (surface)->malloc_data = NULL;
+ }
+
+ if (!surface->ddrawsink) {
+ goto no_sink;
+ }
+
+ /* Release the ref to our sink */
+ surface->ddrawsink = NULL;
+ gst_object_unref (ddrawsink);
+
+ return;
+
+no_sink:
+ GST_WARNING ("no sink found in surface");
+ return;
+}
+
+static void
+gst_directdrawsink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
+{
+ g_mutex_lock (ddrawsink->pool_lock);
+ while (ddrawsink->buffer_pool) {
+ GstDDrawSurface *surface = ddrawsink->buffer_pool->data;
+
+ ddrawsink->buffer_pool = g_slist_delete_link (ddrawsink->buffer_pool,
+ ddrawsink->buffer_pool);
+ gst_directdrawsink_surface_destroy (ddrawsink, surface);
+ }
+ g_mutex_unlock (ddrawsink->pool_lock);
+}
+
+static void
+gst_directdrawsink_cleanup (GstDirectDrawSink * ddrawsink)
+{
+ /* Post quit message and wait for our event window thread */
+ if (ddrawsink->video_window)
+ PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
+ if (ddrawsink->window_thread) {
+ g_thread_join (ddrawsink->window_thread);
+ ddrawsink->window_thread = NULL;
+ }
+
+ if (ddrawsink->buffer_pool) {
+ gst_directdrawsink_bufferpool_clear (ddrawsink);
+ ddrawsink->buffer_pool = NULL;
+ }
+
+ if (ddrawsink->display_modes) {
+ GSList *walk = ddrawsink->display_modes;
+
+ while (walk) {
+ g_free (walk->data);
+ walk = g_slist_next (walk);
+ }
+ g_slist_free (ddrawsink->display_modes);
+ ddrawsink->display_modes = NULL;
+ }
+
+ if (ddrawsink->overlays) {
+ IDirectDrawSurface_Release (ddrawsink->overlays);
+ ddrawsink->overlays = NULL;
+ }
+
+ if (ddrawsink->offscreen_surface) {
+ IDirectDrawSurface_Release (ddrawsink->offscreen_surface);
+ ddrawsink->offscreen_surface = NULL;
+ }
+
+ if (ddrawsink->clipper) {
+ IDirectDrawClipper_Release (ddrawsink->clipper);
+ ddrawsink->clipper = NULL;
+ }
+
+ if (ddrawsink->primary_surface) {
+ IDirectDrawSurface_Release (ddrawsink->primary_surface);
+ ddrawsink->primary_surface = NULL;
+ }
+
+ if (ddrawsink->ddraw_object) {
+ IDirectDraw_Release (ddrawsink->ddraw_object);
+ ddrawsink->ddraw_object = NULL;
+ }
+
+ ddrawsink->setup = FALSE;
+}
diff --git a/sys/directdraw/gstdirectdrawsink.h b/sys/directdraw/gstdirectdrawsink.h
new file mode 100644
index 000000000..7476eaac2
--- /dev/null
+++ b/sys/directdraw/gstdirectdrawsink.h
@@ -0,0 +1,132 @@
+/* GStreamer
+ * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdirectdrawsink.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_DIRECTDRAWSINK_H__
+#define __GST_DIRECTDRAWSINK_H__
+
+#define DIRECTDRAW_VERSION 0x0700
+
+#include <gst/gst.h>
+#include <gst/video/gstvideosink.h>
+#include <windows.h>
+
+#include <ddraw.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_DIRECTDRAW_SINK (gst_directdrawsink_get_type())
+#define GST_DIRECTDRAW_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRECTDRAW_SINK,GstDirectDrawSink))
+#define GST_DIRECTDRAW_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRECTDRAW_SINK,GstDirectDrawSinkClass))
+#define GST_IS_DIRECTDRAW_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRECTDRAW_SINK))
+#define GST_IS_DIRECTDRAW_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRECTDRAW_SINK))
+typedef struct _GstDirectDrawSink GstDirectDrawSink;
+typedef struct _GstDirectDrawSinkClass GstDirectDrawSinkClass;
+
+#define GST_TYPE_DDRAWSURFACE (gst_ddrawsurface_get_type())
+#define GST_IS_DDRAWSURFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DDRAWSURFACE))
+#define GST_DDRAWSURFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DDRAWSURFACE, GstDDrawSurface))
+
+typedef struct _GstDDrawSurface GstDDrawSurface;
+
+struct _GstDDrawSurface
+{
+ /* Extension of GstBuffer to store directdraw surfaces */
+ GstBuffer buffer;
+
+ /*directdraw surface */
+ LPDIRECTDRAWSURFACE surface;
+
+ gint width;
+ gint height;
+ gboolean locked;
+
+ DDPIXELFORMAT dd_pixel_format;
+
+ GstDirectDrawSink *ddrawsink;
+};
+
+
+typedef struct _GstDDDDisplayMode GstDDDisplayMode;
+
+struct _GstDDDDisplayMode
+{
+ gint width;
+ gint height;
+ gint bpp;
+};
+
+struct _GstDirectDrawSink
+{
+ GstVideoSink videosink;
+
+ /*directdraw offscreen surfaces pool */
+ GSList *buffer_pool;
+
+ GSList *display_modes;
+ //GstDDDisplayMode display_mode;
+
+ /*directdraw objects */
+ LPDIRECTDRAW ddraw_object;
+ LPDIRECTDRAWSURFACE primary_surface;
+ LPDIRECTDRAWSURFACE offscreen_surface;
+ LPDIRECTDRAWSURFACE overlays;
+ LPDIRECTDRAWCLIPPER clipper;
+ LPDIRECTDRAWSURFACE extern_surface;
+
+ /*Directdraw caps */
+ GstCaps *caps;
+
+ /*handle of the video window */
+ HWND video_window;
+ gboolean resize_window;
+
+ /*video properties */
+ gint video_width, video_height;
+ gint out_width, out_height;
+ //gdouble framerate;
+ gint fps_n;
+ gint fps_d;
+
+ /*pixel format */
+ DDPIXELFORMAT dd_pixel_format;
+
+ GThread *window_thread;
+
+ gboolean bUseOverlay;
+ gboolean bIsOverlayVisible;
+ gboolean bFullScreen;
+ gboolean setup;
+
+ GMutex *pool_lock;
+
+ guint color_key;
+ /*LPDIRECTDRAWSURFACE extern_surface; */
+};
+
+struct _GstDirectDrawSinkClass
+{
+ GstVideoSinkClass parent_class;
+};
+
+GType gst_directdrawsink_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_DIRECTDRAWSINK_H__ */