summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Moutte <sebastien@moutte.net>2006-01-05 23:17:44 +0000
committerSébastien Moutte <sebastien@moutte.net>2006-01-05 23:17:44 +0000
commitf670909edbd4a95cfed93b4db85cb5ba93a17461 (patch)
tree2cac66ceba3a2dbbcb6c95aa79723d3619ca0eeb
parent4e68e0f563a26230c0d0d33c4859d7975a6e09e2 (diff)
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
-rw-r--r--sys/directsound/gstdirectsoundplugin.c43
-rw-r--r--sys/directsound/gstdirectsoundsink.c421
-rw-r--r--sys/directsound/gstdirectsoundsink.h68
-rw-r--r--win32/vs6/libgstdirectdraw.dsp125
-rw-r--r--win32/vs6/libgstdirectsound.dsp125
8 files changed, 2689 insertions, 0 deletions
diff --git a/sys/directdraw/gstdirectdrawplugin.c b/sys/directdraw/gstdirectdrawplugin.c
new file mode 100644
index 00000000..69d79507
--- /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 00000000..55a0d54a
--- /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 00000000..7476eaac
--- /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__ */
diff --git a/sys/directsound/gstdirectsoundplugin.c b/sys/directsound/gstdirectsoundplugin.c
new file mode 100644
index 00000000..c789b2bf
--- /dev/null
+++ b/sys/directsound/gstdirectsoundplugin.c
@@ -0,0 +1,43 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstdirectsoundplugin.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 "gstdirectsoundsink.h"
+
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "directsoundsink", GST_RANK_NONE,
+ GST_TYPE_DIRECTSOUND_SINK))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "directsound",
+ "DIRECTSOUND plugin library",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)
diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c
new file mode 100644
index 00000000..3d7ab997
--- /dev/null
+++ b/sys/directsound/gstdirectsoundsink.c
@@ -0,0 +1,421 @@
+/* GStreamer
+* Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+*
+* gstdirectsoundsink.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 "gstdirectsoundsink.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY_STATIC (directsoundsink_debug);
+#define GST_CAT_DEFAULT directsoundsink_debug
+
+/* elementfactory information */
+static GstElementDetails gst_directsoundsink_details =
+GST_ELEMENT_DETAILS ("Audio Sink (DIRECTSOUND)",
+ "Sink/Audio",
+ "Output to a sound card via DIRECTSOUND",
+ "Sebastien Moutte <sebastien@moutte.net>");
+
+static void gst_directsoundsink_base_init (gpointer g_class);
+static void gst_directsoundsink_class_init (GstDirectSoundSinkClass * klass);
+static void gst_directsoundsink_init (GstDirectSoundSink * alsasink);
+static void gst_directsoundsink_dispose (GObject * object);
+static void gst_directsoundsink_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_directsoundsink_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_directsoundsink_getcaps (GstBaseSink * bsink);
+
+static gboolean gst_directsoundsink_prepare (GstAudioSink * asink,
+ GstRingBufferSpec * spec);
+static gboolean gst_directsoundsink_unprepare (GstAudioSink * asink);
+
+static gboolean gst_directsoundsink_open (GstAudioSink * asink);
+static gboolean gst_directsoundsink_close (GstAudioSink * asink);
+static guint gst_directsoundsink_write (GstAudioSink * asink, gpointer data,
+ guint length);
+static guint gst_directsoundsink_delay (GstAudioSink * asink);
+static void gst_directsoundsink_reset (GstAudioSink * asink);
+
+
+static GstStaticPadTemplate directsoundsink_sink_factory =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
+ "audio/x-raw-int, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
+
+static void
+_do_init (GType directsoundsink_type)
+{
+ GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0,
+ "DirectSound sink");
+}
+
+GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsoundsink, GstAudioSink,
+ GST_TYPE_AUDIO_SINK, _do_init);
+
+static void
+gst_directsoundsink_dispose (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_directsoundsink_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &gst_directsoundsink_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&directsoundsink_sink_factory));
+}
+
+static void
+gst_directsoundsink_class_init (GstDirectSoundSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+ GstBaseAudioSinkClass *gstbaseaudiosink_class;
+ GstAudioSinkClass *gstaudiosink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
+ gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+ parent_class = g_type_class_ref (GST_TYPE_DIRECTSOUND_SINK);
+
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_directsoundsink_dispose);
+ gobject_class->get_property =
+ GST_DEBUG_FUNCPTR (gst_directsoundsink_get_property);
+ gobject_class->set_property =
+ GST_DEBUG_FUNCPTR (gst_directsoundsink_set_property);
+
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_directsoundsink_getcaps);
+
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_directsoundsink_prepare);
+ gstaudiosink_class->unprepare =
+ GST_DEBUG_FUNCPTR (gst_directsoundsink_unprepare);
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_directsoundsink_open);
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_directsoundsink_close);
+ gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_directsoundsink_write);
+
+ gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_directsoundsink_delay);
+ gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_directsoundsink_reset);
+}
+
+static void
+gst_directsoundsink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstDirectSoundSink *dsoundsink;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_directsoundsink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstDirectSoundSink *dsoundsink;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_directsoundsink_init (GstDirectSoundSink * dsoundsink,
+ GstDirectSoundSinkClass g_class)
+{
+ GST_DEBUG ("initializing directsoundsink");
+
+ dsoundsink->pDS = NULL;
+ dsoundsink->pDSBSecondary = NULL;
+ dsoundsink->current_circular_offset = 0;
+ dsoundsink->buffer_size = DSBSIZE_MIN;
+}
+
+static GstCaps *
+gst_directsoundsink_getcaps (GstBaseSink * bsink)
+{
+ GstDirectSoundSink *dsoundsink;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (bsink);
+
+ return
+ gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
+ (dsoundsink)));
+}
+
+static gboolean
+gst_directsoundsink_open (GstAudioSink * asink)
+{
+ GstDirectSoundSink *dsoundsink;
+ HRESULT hRes;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /* create and initialize a DirecSound object */
+ if (FAILED (hRes = DirectSoundCreate (NULL, &dsoundsink->pDS, NULL))) {
+ GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+ ("gst_directsoundsink_open: DirectSoundCreate: %s",
+ DXGetErrorString9 (hRes)), (NULL));
+ return FALSE;
+ }
+
+ if (FAILED (hRes =
+ IDirectSound_SetCooperativeLevel (dsoundsink->pDS,
+ GetDesktopWindow (), DSSCL_PRIORITY))) {
+ GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+ ("gst_directsoundsink_open: IDirectSound_SetCooperativeLevel: %s",
+ DXGetErrorString9 (hRes)), (NULL));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_directsoundsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+{
+ GstDirectSoundSink *dsoundsink;
+ HRESULT hRes;
+ DSBUFFERDESC descSecondary;
+ WAVEFORMATEX wfx;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /*save number of bytes per sample */
+ dsoundsink->bytes_per_sample = spec->bytes_per_sample;
+
+ /* fill the WAVEFORMATEX struture with spec params */
+ memset (&wfx, 0, sizeof (wfx));
+ wfx.cbSize = sizeof (wfx);
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = spec->channels;
+ wfx.nSamplesPerSec = spec->rate;
+ wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels;
+ wfx.nBlockAlign = spec->bytes_per_sample;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+
+ GST_DEBUG
+ ("GstRingBufferSpec->channels: %d, GstRingBufferSpec->rate: %d, GstRingBufferSpec->bytes_per_sample: %d\n"
+ "WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d, WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n",
+ spec->channels, spec->rate, spec->bytes_per_sample, wfx.nSamplesPerSec,
+ wfx.wBitsPerSample, wfx.nBlockAlign, wfx.nAvgBytesPerSec);
+
+ /* directsound buffer size can handle 2 secs of the stream */
+ dsoundsink->buffer_size = wfx.nAvgBytesPerSec / 2;
+
+ /* create a secondary directsound buffer */
+ memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
+ descSecondary.dwSize = sizeof (DSBUFFERDESC);
+ descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 |
+ DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;
+
+ descSecondary.dwBufferBytes = dsoundsink->buffer_size;
+ descSecondary.lpwfxFormat = (WAVEFORMATEX *) & wfx;
+
+ hRes = IDirectSound_CreateSoundBuffer (dsoundsink->pDS, &descSecondary,
+ &dsoundsink->pDSBSecondary, NULL);
+ if (FAILED (hRes)) {
+ GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
+ ("gst_directsoundsink_prepare: IDirectSound_CreateSoundBuffer: %s",
+ DXGetErrorString9 (hRes)), (NULL));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_directsoundsink_unprepare (GstAudioSink * asink)
+{
+ GstDirectSoundSink *dsoundsink;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /* release secondary DirectSound buffer */
+ if (dsoundsink->pDSBSecondary)
+ IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary);
+
+ return TRUE;
+}
+
+static gboolean
+gst_directsoundsink_close (GstAudioSink * asink)
+{
+ GstDirectSoundSink *dsoundsink = NULL;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /* release DirectSound object */
+ g_return_val_if_fail (dsoundsink->pDS != NULL, FALSE);
+ IDirectSound_Release (dsoundsink->pDS);
+
+ return TRUE;
+}
+
+
+static guint
+gst_directsoundsink_write (GstAudioSink * asink, gpointer data, guint length)
+{
+ GstDirectSoundSink *dsoundsink;
+ DWORD dwStatus;
+ HRESULT hRes;
+ LPVOID pLockedBuffer1 = NULL, pLockedBuffer2 = NULL;
+ DWORD dwSizeBuffer1, dwSizeBuffer2;
+ DWORD dwCurrentPlayCursor;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /* get current buffer status */
+ hRes = IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus);
+
+ /* get current play cursor position */
+ hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+ &dwCurrentPlayCursor, NULL);
+ if (SUCCEEDED (hRes) && (dwStatus & DSBSTATUS_PLAYING)) {
+ DWORD dwFreeBufferSize;
+
+ calculate_freesize:
+ /* calculate the free size of the circular buffer */
+ if (dwCurrentPlayCursor < dsoundsink->current_circular_offset)
+ dwFreeBufferSize =
+ dsoundsink->buffer_size - (dsoundsink->current_circular_offset -
+ dwCurrentPlayCursor);
+ else
+ dwFreeBufferSize =
+ dwCurrentPlayCursor - dsoundsink->current_circular_offset;
+
+ if (length >= dwFreeBufferSize) {
+ Sleep (100);
+ hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+ &dwCurrentPlayCursor, NULL);
+ goto calculate_freesize;
+ }
+ }
+
+ if (dwStatus & DSBSTATUS_BUFFERLOST) {
+ hRes = IDirectSoundBuffer_Restore (dsoundsink->pDSBSecondary); /*need a loop waiting the buffer is restored?? */
+
+ dsoundsink->current_circular_offset = 0;
+ }
+
+ hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary,
+ dsoundsink->current_circular_offset, length, &pLockedBuffer1,
+ &dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);
+
+ if (SUCCEEDED (hRes)) {
+ // Write to pointers without reordering.
+ memcpy (pLockedBuffer1, data, dwSizeBuffer1);
+ if (pLockedBuffer2 != NULL)
+ memcpy (pLockedBuffer2, (LPBYTE) data + dwSizeBuffer1, dwSizeBuffer2);
+
+ // Update where the buffer will lock (for next time)
+ dsoundsink->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2;
+ dsoundsink->current_circular_offset %= dsoundsink->buffer_size; /* Circular buffer */
+
+ hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1,
+ dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2);
+ }
+
+ /* if the buffer was not in playing state yet, call play on the buffer */
+ if (!(dwStatus & DSBSTATUS_PLAYING)) {
+ hRes = IDirectSoundBuffer_Play (dsoundsink->pDSBSecondary, 0, 0,
+ DSBPLAY_LOOPING);
+ }
+
+ return length;
+}
+
+static guint
+gst_directsoundsink_delay (GstAudioSink * asink)
+{
+ GstDirectSoundSink *dsoundsink;
+ HRESULT hRes;
+ DWORD dwCurrentPlayCursor;
+ DWORD dwBytesInQueue = 0;
+ gint nNbSamplesInQueue = 0;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ /*evaluate the number of samples in queue in the circular buffer */
+ hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
+ &dwCurrentPlayCursor, NULL);
+
+ if (hRes == S_OK) {
+ if (dwCurrentPlayCursor < dsoundsink->current_circular_offset)
+ dwBytesInQueue =
+ dsoundsink->current_circular_offset - dwCurrentPlayCursor;
+ else
+ dwBytesInQueue =
+ dsoundsink->current_circular_offset + (dsoundsink->buffer_size -
+ dwCurrentPlayCursor);
+
+ nNbSamplesInQueue = dwBytesInQueue / dsoundsink->bytes_per_sample;
+ }
+
+ return nNbSamplesInQueue;
+}
+
+static void
+gst_directsoundsink_reset (GstAudioSink * asink)
+{
+ /*not tested for seeking */
+ GstDirectSoundSink *dsoundsink;
+
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
+ IDirectSoundBuffer_Stop (dsoundsink->pDSBSecondary);
+}
diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h
new file mode 100644
index 00000000..54f7148e
--- /dev/null
+++ b/sys/directsound/gstdirectsoundsink.h
@@ -0,0 +1,68 @@
+/* GStreamer
+ * Copyright (C) 2005 Sebastien Moutte <sebastien@moutte.net>
+ *
+ * gstdirectsoundsink.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_DIRECTSOUNDSINK_H__
+#define __GST_DIRECTSOUNDSINK_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+#include <windows.h>
+#include <dxerr9.h>
+#include <dsound.h>
+
+
+G_BEGIN_DECLS
+#define GST_TYPE_DIRECTSOUND_SINK (gst_directsoundsink_get_type())
+#define GST_DIRECTSOUND_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSink))
+#define GST_DIRECTSOUND_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRECTSOUND_SINK,GstDirectSoundSinkClass))
+#define GST_IS_DIRECTSOUND_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRECTSOUND_SINK))
+#define GST_IS_DIRECTSOUND_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRECTSOUND_SINK))
+typedef struct _GstDirectSoundSink GstDirectSoundSink;
+typedef struct _GstDirectSoundSinkClass GstDirectSoundSinkClass;
+
+struct _GstDirectSoundSink
+{
+ GstAudioSink sink;
+
+ LPDIRECTSOUND pDS;
+
+ LPDIRECTSOUNDBUFFER pDSBSecondary;
+
+ /*DirectSound buffer size */
+ guint buffer_size;
+
+ /*Offset of the circular buffer where we must write next */
+ guint current_circular_offset;
+
+ guint bytes_per_sample;
+};
+
+struct _GstDirectSoundSinkClass
+{
+ GstAudioSinkClass parent_class;
+};
+
+GType gst_directsoundsink_get_type (void);
+
+G_END_DECLS
+#endif /* __GST_DIRECTSOUNDSINK_H__ */
diff --git a/win32/vs6/libgstdirectdraw.dsp b/win32/vs6/libgstdirectdraw.dsp
new file mode 100644
index 00000000..37432a96
--- /dev/null
+++ b/win32/vs6/libgstdirectdraw.dsp
@@ -0,0 +1,125 @@
+# Microsoft Developer Studio Project File - Name="libgstdirectdraw" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libgstdirectdraw - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libgstdirectdraw.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libgstdirectdraw.mak" CFG="libgstdirectdraw - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libgstdirectdraw - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libgstdirectdraw - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libgstdirectdraw - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTDRAW_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTDRAW_EXPORTS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 libgstreamer-0.10.lib libgstbase-0.10.lib libgstvideo-0.10.lib glib-2.0.lib gobject-2.0.lib user32.lib gdi32.lib ddraw.lib /nologo /dll /machine:I386 /libpath:"../../../gstreamer/win32/vs6/release" /libpath:"../../../gst-plugins-base/win32/vs6/release" /libpath:"./release"
+# Begin Special Build Tool
+TargetPath=.\Release\libgstdirectdraw.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libgstdirectdraw - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTDRAW_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTDRAW_EXPORTS" /D "HAVE_CONFIG_H" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libgstreamer-0.10.lib libgstbase-0.10.lib libgstvideo-0.10.lib glib-2.0D.lib gobject-2.0D.lib ddraw.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug"
+# Begin Special Build Tool
+TargetPath=.\Debug\libgstdirectdraw.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\debug\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libgstdirectdraw - Win32 Release"
+# Name "libgstdirectdraw - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\sys\directdraw\gstdirectdrawplugin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\sys\directdraw\gstdirectdrawsink.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\sys\directdraw\gstdirectdrawsink.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/win32/vs6/libgstdirectsound.dsp b/win32/vs6/libgstdirectsound.dsp
new file mode 100644
index 00000000..859dd7df
--- /dev/null
+++ b/win32/vs6/libgstdirectsound.dsp
@@ -0,0 +1,125 @@
+# Microsoft Developer Studio Project File - Name="libgstdirectsound" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libgstdirectsound - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libgstdirectsound.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libgstdirectsound.mak" CFG="libgstdirectsound - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libgstdirectsound - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libgstdirectsound - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libgstdirectsound - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTSOUND_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /I "../.." /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTSOUND_EXPORTS" /D "HAVE_CONFIG_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 libgstreamer-0.10.lib libgstbase-0.10.lib libgstaudio-0.10.lib glib-2.0.lib gobject-2.0.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /machine:I386 /libpath:"../../../gstreamer/win32/vs6/release" /libpath:"../../../gst-plugins-base/win32/vs6/release" /libpath:"./release"
+# Begin Special Build Tool
+TargetPath=.\Release\libgstdirectsound.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libgstdirectsound - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTSOUND_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "../../gst-libs" /I "../../../gstreamer" /I "../common" /I "../../../gstreamer/libs" /I "../../../gst-plugins-base/gst-libs" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDIRECTSOUND_EXPORTS" /D "HAVE_CONFIG_H" /FR /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libgstreamer-0.10.lib libgstbase-0.10.lib libgstaudio-0.10.lib glib-2.0D.lib gobject-2.0D.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug"
+# Begin Special Build Tool
+TargetPath=.\Debug\libgstdirectsound.dll
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\debug\lib\gstreamer-0.10
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libgstdirectsound - Win32 Release"
+# Name "libgstdirectsound - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\sys\directsound\gstdirectsoundplugin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\sys\directsound\gstdirectsoundsink.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\sys\directsound\gstdirectsoundsink.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project