From f670909edbd4a95cfed93b4db85cb5ba93a17461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Moutte?= Date: Thu, 5 Jan 2006 23:17:44 +0000 Subject: [PATCH] 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 * 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 --- sys/directdraw/gstdirectdrawplugin.c | 42 + sys/directdraw/gstdirectdrawsink.c | 1733 ++++++++++++++++++++++++ sys/directdraw/gstdirectdrawsink.h | 132 ++ sys/directsound/gstdirectsoundplugin.c | 43 + sys/directsound/gstdirectsoundsink.c | 421 ++++++ sys/directsound/gstdirectsoundsink.h | 68 + win32/vs6/libgstdirectdraw.dsp | 125 ++ win32/vs6/libgstdirectsound.dsp | 125 ++ 8 files changed, 2689 insertions(+) create mode 100644 sys/directdraw/gstdirectdrawplugin.c create mode 100644 sys/directdraw/gstdirectdrawsink.c create mode 100644 sys/directdraw/gstdirectdrawsink.h create mode 100644 sys/directsound/gstdirectsoundplugin.c create mode 100644 sys/directsound/gstdirectsoundsink.c create mode 100644 sys/directsound/gstdirectsoundsink.h create mode 100644 win32/vs6/libgstdirectdraw.dsp create mode 100644 win32/vs6/libgstdirectsound.dsp diff --git a/sys/directdraw/gstdirectdrawplugin.c b/sys/directdraw/gstdirectdrawplugin.c new file mode 100644 index 0000000000..69d795074e --- /dev/null +++ b/sys/directdraw/gstdirectdrawplugin.c @@ -0,0 +1,42 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 0000000000..55a0d54a1f --- /dev/null +++ b/sys/directdraw/gstdirectdrawsink.c @@ -0,0 +1,1733 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 +#include +#include +#include + +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 "); + +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 0000000000..7476eaac23 --- /dev/null +++ b/sys/directdraw/gstdirectdrawsink.h @@ -0,0 +1,132 @@ +/* GStreamer + * Copyright (C) 2005 Sebastien Moutte + * + * 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 +#include +#include + +#include + +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 0000000000..c789b2bf16 --- /dev/null +++ b/sys/directsound/gstdirectsoundplugin.c @@ -0,0 +1,43 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 0000000000..3d7ab9978e --- /dev/null +++ b/sys/directsound/gstdirectsoundsink.c @@ -0,0 +1,421 @@ +/* GStreamer +* Copyright (C) 2005 Sebastien Moutte +* +* 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 +#include +#include +#include + +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 "); + +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 0000000000..54f7148e78 --- /dev/null +++ b/sys/directsound/gstdirectsoundsink.h @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 2005 Sebastien Moutte + * + * 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 +#include + +#include +#include +#include + + +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 0000000000..37432a96b3 --- /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 0000000000..859dd7df02 --- /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