2006-01-05 23:17:44 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/**
|
|
|
|
* SECTION:element-directdrawsink
|
|
|
|
*
|
|
|
|
* <refsect2>
|
|
|
|
* <para>
|
|
|
|
* DirectdrawSink renders video frames to any win32 window. This element can receive
|
|
|
|
* a window ID from the application through the XOverlay interface and will then render
|
|
|
|
* video frames in this drawable.
|
|
|
|
* If no Window ID was provided by the application, the element will create its
|
|
|
|
* own internal window and render into it.
|
|
|
|
* </para>
|
|
|
|
* </refsect2>
|
|
|
|
*/
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "gstdirectdrawsink.h"
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
2006-11-01 10:19:18 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2006-01-05 23:17:44 +00:00
|
|
|
#include <unistd.h>
|
2006-11-01 10:19:18 +00:00
|
|
|
#endif
|
2006-01-05 23:17:44 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (directdrawsink_debug);
|
|
|
|
#define GST_CAT_DEFAULT directdrawsink_debug
|
|
|
|
|
|
|
|
/* elementfactory information */
|
2006-04-25 21:56:38 +00:00
|
|
|
static const GstElementDetails gst_directdrawsink_details =
|
2006-01-05 23:17:44 +00:00
|
|
|
GST_ELEMENT_DETAILS ("Video Sink (DIRECTDRAW)",
|
|
|
|
"Sink/Video",
|
|
|
|
"Output to a video card via DIRECTDRAW",
|
|
|
|
"Sebastien Moutte <sebastien@moutte.net>");
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
static void gst_directdrawsink_init_interfaces (GType type);
|
|
|
|
|
|
|
|
GST_BOILERPLATE_FULL (GstDirectDrawSink, gst_directdrawsink, GstVideoSink,
|
|
|
|
GST_TYPE_VIDEO_SINK, gst_directdrawsink_init_interfaces);
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
static void
|
|
|
|
gst_directdrawsink_ddraw_put (GstDirectDrawSink * ddrawsink,
|
|
|
|
GstDDrawSurface * surface);
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* surfaces management functions */
|
2006-01-05 23:17:44 +00:00
|
|
|
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, "
|
|
|
|
"framerate = (fraction) [ 0, MAX ], "
|
2007-02-11 15:26:49 +00:00
|
|
|
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]"
|
|
|
|
/* "; "
|
|
|
|
"video/x-raw-yuv, "
|
2006-01-05 23:17:44 +00:00
|
|
|
"framerate = (fraction) [ 0, MAX ], "
|
|
|
|
"width = (int) [ 1, MAX ], "
|
|
|
|
"height = (int) [ 1, MAX ], "
|
2007-02-11 15:26:49 +00:00
|
|
|
"format = (fourcc) YV12"
|
|
|
|
*/
|
|
|
|
)
|
2006-01-05 23:17:44 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_SURFACE,
|
2006-07-24 21:43:06 +00:00
|
|
|
PROP_KEEP_ASPECT_RATIO
|
2006-01-05 23:17:44 +00:00
|
|
|
};
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* interfaces stuff */
|
|
|
|
static gboolean
|
|
|
|
gst_directdrawsink_interface_supported (GstImplementsInterface * iface,
|
|
|
|
GType type)
|
|
|
|
{
|
|
|
|
g_assert (type == GST_TYPE_X_OVERLAY);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_directdrawsink_interface_init (GstImplementsInterfaceClass * klass)
|
|
|
|
{
|
|
|
|
klass->supported = gst_directdrawsink_interface_supported;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_directdrawsink_set_window_id (GstXOverlay * overlay, ULONG window_id)
|
|
|
|
{
|
|
|
|
GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
|
|
|
|
|
|
|
|
/* check if we are already using this window id */
|
|
|
|
if (ddrawsink->video_window == (HWND) window_id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (window_id) {
|
|
|
|
HRESULT hres;
|
|
|
|
|
|
|
|
ddrawsink->video_window = (HWND) window_id;
|
|
|
|
ddrawsink->our_video_window = FALSE;
|
|
|
|
|
|
|
|
if (ddrawsink->setup) {
|
|
|
|
/* update the clipper object with the new window */
|
|
|
|
hres = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
|
|
|
|
ddrawsink->video_window);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_directdrawsink_expose (GstXOverlay * overlay)
|
|
|
|
{
|
|
|
|
GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (overlay);
|
|
|
|
|
|
|
|
gst_directdrawsink_show_frame (GST_BASE_SINK (ddrawsink), NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_directdrawsink_xoverlay_interface_init (GstXOverlayClass * iface)
|
|
|
|
{
|
|
|
|
iface->set_xwindow_id = gst_directdrawsink_set_window_id;
|
|
|
|
iface->expose = gst_directdrawsink_expose;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_directdrawsink_init_interfaces (GType type)
|
|
|
|
{
|
|
|
|
static const GInterfaceInfo iface_info = {
|
|
|
|
(GInterfaceInitFunc) gst_directdrawsink_interface_init,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const GInterfaceInfo xoverlay_info = {
|
|
|
|
(GInterfaceInitFunc) gst_directdrawsink_xoverlay_interface_init,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
|
|
|
|
&iface_info);
|
|
|
|
g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
/* 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);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
if (!(structure = gst_caps_get_structure (caps, 0))) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug,
|
|
|
|
"can't get structure pointer from caps");
|
2006-01-05 23:17:44 +00:00
|
|
|
return FALSE;
|
2007-02-11 15:26:49 +00:00
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
|
2007-02-11 15:26:49 +00:00
|
|
|
gint depth, bitcount, bitmask, endianness;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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;
|
2007-02-11 15:26:49 +00:00
|
|
|
|
|
|
|
gst_structure_get_int (structure, "endianness", &endianness);
|
|
|
|
if (endianness == G_BIG_ENDIAN) {
|
|
|
|
endianness = G_LITTLE_ENDIAN;
|
|
|
|
pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
|
|
|
|
pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
|
|
|
|
pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
|
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
} 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 {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"unknown caps name received %" GST_PTR_FORMAT, caps);
|
2006-01-05 23:17:44 +00:00
|
|
|
ret = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-01-03 19:54:33 +00:00
|
|
|
/*
|
2006-01-05 23:17:44 +00:00
|
|
|
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",
|
2007-02-11 15:26:49 +00:00
|
|
|
"bpp", G_TYPE_INT, bpp,
|
2006-01-05 23:17:44 +00:00
|
|
|
"depth", G_TYPE_INT, depth,
|
2007-02-11 15:26:49 +00:00
|
|
|
"endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
|
|
|
|
NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((pixel_format.dwFlags & DDPF_YUV) == DDPF_YUV) {
|
|
|
|
fourcc = pixel_format.dwFourCC;
|
|
|
|
caps = gst_caps_new_simple ("video/x-raw-yuv",
|
2007-02-11 15:26:49 +00:00
|
|
|
"format", GST_TYPE_FOURCC, fourcc,
|
|
|
|
NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (caps != NULL);
|
|
|
|
|
|
|
|
return caps;
|
|
|
|
}
|
2007-01-03 19:54:33 +00:00
|
|
|
*/
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
2007-01-03 19:54:33 +00:00
|
|
|
"source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
|
2006-07-24 21:43:06 +00:00
|
|
|
src_width, src_height, dst_width, dst_heigth,
|
|
|
|
result->right - result->left, result->bottom - result->top, result->left,
|
|
|
|
result->right);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/************************************************************************/
|
|
|
|
/* subclass of GstBuffer which manages surfaces lifetime */
|
|
|
|
/* */
|
|
|
|
/************************************************************************/
|
2006-01-05 23:17:44 +00:00
|
|
|
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)
|
|
|
|
) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"destroy image as its size changed %dx%d vs current %dx%d",
|
|
|
|
surface->width, surface->height, ddrawsink->video_width,
|
|
|
|
ddrawsink->video_height);
|
2006-01-05 23:17:44 +00:00
|
|
|
gst_directdrawsink_surface_destroy (ddrawsink, surface);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* In that case we can reuse the image and add it to our image pool. */
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug, "recycling image in pool");
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
/* 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:
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug, "no sink found");
|
2006-01-05 23:17:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gst_ddrawsurface_init (GstDDrawSurface * surface, gpointer g_class)
|
|
|
|
{
|
|
|
|
surface->surface = NULL;
|
|
|
|
surface->width = 0;
|
|
|
|
surface->height = 0;
|
|
|
|
surface->ddrawsink = NULL;
|
2006-03-03 23:45:23 +00:00
|
|
|
surface->locked = FALSE;
|
|
|
|
surface->system_memory = FALSE;
|
2006-01-05 23:17:44 +00:00
|
|
|
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 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;
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_DEBUG_CATEGORY_INIT (directdrawsink_debug, "directdrawsink", 0,
|
|
|
|
"Direct draw sink");
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
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 */
|
|
|
|
/*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));
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
/*setup aspect ratio mode */
|
|
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
|
|
|
PROP_KEEP_ASPECT_RATIO, g_param_spec_boolean ("keep-aspect-ratio",
|
|
|
|
"keep-aspect-ratio", "boolean to video keep aspect ratio", FALSE,
|
|
|
|
G_PARAM_READWRITE));
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
/*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;
|
2006-07-24 21:43:06 +00:00
|
|
|
case PROP_KEEP_ASPECT_RATIO:
|
|
|
|
ddrawsink->keep_aspect_ratio = g_value_get_boolean (value);
|
2006-01-05 23:17:44 +00:00
|
|
|
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) {
|
2006-07-24 21:43:06 +00:00
|
|
|
case PROP_KEEP_ASPECT_RATIO:
|
|
|
|
g_value_set_boolean (value, ddrawsink->keep_aspect_ratio);
|
|
|
|
break;
|
2006-01-05 23:17:44 +00:00
|
|
|
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;
|
2007-02-11 15:26:49 +00:00
|
|
|
ddrawsink->video_window = NULL;
|
|
|
|
ddrawsink->our_video_window = TRUE;
|
|
|
|
ddrawsink->last_buffer = NULL;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
/*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;
|
2006-07-24 21:43:06 +00:00
|
|
|
ddrawsink->bUseOverlay = FALSE;
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->color_key = 0; /*need to be a public property and may be we can enable overlays when this property is set ... */
|
|
|
|
|
|
|
|
ddrawsink->setup = FALSE;
|
|
|
|
|
|
|
|
ddrawsink->buffer_pool = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
ddrawsink->pool_lock = g_mutex_new ();
|
2007-02-11 15:26:49 +00:00
|
|
|
ddrawsink->keep_aspect_ratio = FALSE;
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"getcaps called and we are not setup yet, " "returning template %"
|
|
|
|
GST_PTR_FORMAT, caps);
|
2006-01-05 23:17:44 +00:00
|
|
|
} 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);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug, "set_caps");
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
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);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* Notify application to set window id now */
|
|
|
|
if (!ddrawsink->video_window) {
|
|
|
|
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ddrawsink));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we are rendering to our own window, resize it to video size */
|
|
|
|
if (ddrawsink->video_window && ddrawsink->our_video_window) {
|
2006-01-05 23:17:44 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* create an offscreen surface with the caps */
|
2006-07-24 21:43:06 +00:00
|
|
|
ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
|
|
|
|
if (!ret && ddrawsink->bUseOverlay) {
|
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"Can not create overlay surface, reverting to no overlay display");
|
|
|
|
ddrawsink->bUseOverlay = FALSE;
|
|
|
|
ret = gst_directdrawsink_create_ddraw_surfaces (ddrawsink);
|
|
|
|
if (ret) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/*could not create draw surfaces even with fallback, so leave everything as is */
|
2006-07-24 21:43:06 +00:00
|
|
|
ddrawsink->bUseOverlay = TRUE;
|
|
|
|
}
|
|
|
|
if (!ret) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug, "Can not create ddraw surface");
|
|
|
|
}
|
2007-02-11 15:26:49 +00:00
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
return ret;
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
|
|
|
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:
|
|
|
|
break;
|
|
|
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
|
|
|
break;
|
|
|
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
|
|
|
break;
|
|
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
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 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);
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug, "a buffer of %d bytes was requested",
|
|
|
|
size);
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
if (IDirectDrawSurface7_Blt (surface,
|
2006-01-05 23:17:44 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
if (ddrawsink->keep_aspect_ratio) {
|
|
|
|
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);
|
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
gst_directdrawsink_fill_colorkey (surface, ddrawsink->color_key);
|
|
|
|
|
|
|
|
ddofx.dwSize = sizeof (DDOVERLAYFX);
|
|
|
|
ddofx.dckDestColorkey.dwColorSpaceLowValue = ddrawsink->color_key;
|
|
|
|
ddofx.dckDestColorkey.dwColorSpaceHighValue = ddrawsink->color_key;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_UpdateOverlay (ddrawsink->overlays,
|
2006-01-05 23:17:44 +00:00
|
|
|
NULL, surface, &destsurf_rect, DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW,
|
|
|
|
&ddofx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_directdrawsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
|
|
|
{
|
|
|
|
GstDirectDrawSink *ddrawsink;
|
|
|
|
HRESULT hRes;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
DDSURFACEDESC2 surf_desc;
|
2006-01-05 23:17:44 +00:00
|
|
|
RECT destsurf_rect, src_rect;
|
|
|
|
POINT dest_surf_point;
|
|
|
|
LPDIRECTDRAWSURFACE lpSurface = NULL;
|
|
|
|
|
|
|
|
ddrawsink = GST_DIRECTDRAW_SINK (bsink);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
|
|
|
|
if (buf) {
|
|
|
|
/*save a reference to the input buffer */
|
|
|
|
if (ddrawsink->last_buffer != buf) {
|
|
|
|
if (ddrawsink->last_buffer) {
|
|
|
|
GST_LOG_OBJECT (ddrawsink, "unreffing %p", ddrawsink->last_buffer);
|
|
|
|
gst_buffer_unref (ddrawsink->last_buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GST_LOG_OBJECT (ddrawsink, "reffing %p as our current buffer", buf);
|
|
|
|
ddrawsink->last_buffer = gst_buffer_ref (buf);
|
|
|
|
} else {
|
|
|
|
/*use last buffer */
|
|
|
|
buf = ddrawsink->last_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf == NULL)
|
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
if (ddrawsink->keep_aspect_ratio) {
|
2007-02-11 15:26:49 +00:00
|
|
|
/* center image to dest image keeping aspect ratio */
|
2006-07-24 21:43:06 +00:00
|
|
|
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);
|
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
if (ddrawsink->bUseOverlay) {
|
|
|
|
/*get the back buffer of the overlays flipping chain */
|
|
|
|
DDSCAPS ddbackcaps;
|
|
|
|
|
|
|
|
ddbackcaps.dwCaps = DDSCAPS_BACKBUFFER;
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes =
|
|
|
|
IDirectDrawSurface7_GetAttachedSurface (ddrawsink->overlays,
|
|
|
|
&ddbackcaps, &lpSurface);
|
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"gst_directdrawsink_show_frame failed getting overlay backbuffer %s",
|
|
|
|
DDErrorString (hRes));
|
2006-01-05 23:17:44 +00:00
|
|
|
} 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;
|
2007-02-11 15:26:49 +00:00
|
|
|
guint src_pitch;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
/* Check for lost surface */
|
2007-02-11 15:26:49 +00:00
|
|
|
if (IDirectDrawSurface7_IsLost (lpSurface) == DDERR_SURFACELOST) {
|
|
|
|
IDirectDrawSurface7_Restore (lpSurface);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMemory (&surf_desc, sizeof (surf_desc));
|
|
|
|
surf_desc.dwSize = sizeof (surf_desc);
|
|
|
|
|
|
|
|
/* Lock the surface */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Lock (lpSurface, NULL, &surf_desc, DDLOCK_WAIT,
|
2006-01-05 23:17:44 +00:00
|
|
|
NULL);
|
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"gst_directdrawsink_show_frame failed locking surface %s",
|
2006-01-05 23:17:44 +00:00
|
|
|
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 */
|
2007-02-11 15:26:49 +00:00
|
|
|
/* for (line = 0; line < surf_desc.dwHeight; line++) {
|
|
|
|
memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch),
|
|
|
|
src_pitch);
|
2006-01-05 23:17:44 +00:00
|
|
|
data += surf_desc.lPitch;
|
2007-02-11 15:26:49 +00:00
|
|
|
}*/
|
|
|
|
memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
/* Unlock the surface */
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_Unlock (lpSurface, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"gst_directdrawsink_show_frame failed unlocking surface %s",
|
2006-01-05 23:17:44 +00:00
|
|
|
DDErrorString (hRes));
|
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->bUseOverlay) {
|
|
|
|
/*Flip to front overlay */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Flip (ddrawsink->overlays, lpSurface,
|
|
|
|
DDFLIP_WAIT);
|
|
|
|
IDirectDrawSurface7_Release (lpSurface);
|
2006-01-05 23:17:44 +00:00
|
|
|
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 */
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_BltFast (ddrawsink->extern_surface, 0, 0,
|
2006-01-05 23:17:44 +00:00
|
|
|
lpSurface, NULL, DDBLTFAST_WAIT);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Blt (ddrawsink->extern_surface,
|
|
|
|
&destsurf_rect, lpSurface, NULL, DDBLT_WAIT, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*blit to primary surface ( Blt will scale the video the dest rect surface if needed */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
|
2006-01-05 23:17:44 +00:00
|
|
|
lpSurface, NULL, DDBLT_WAIT, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
GstDDrawSurface *surface = NULL;
|
|
|
|
|
|
|
|
surface = GST_DDRAWSURFACE (buf);
|
|
|
|
|
|
|
|
/* Unlocking surface before blit */
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Unlock (surface->surface, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->locked = FALSE;
|
|
|
|
|
|
|
|
/* Check for lost surfaces */
|
2007-02-11 15:26:49 +00:00
|
|
|
if (IDirectDrawSurface7_IsLost (surface->surface) == DDERR_SURFACELOST) {
|
|
|
|
IDirectDrawSurface7_Restore (surface->surface);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->bUseOverlay) {
|
|
|
|
/* blit to the overlays back buffer */
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_Blt (lpSurface, NULL,
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->surface, NULL, DDBLT_WAIT, NULL);
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_Flip (ddrawsink->overlays, NULL, DDFLIP_WAIT);
|
2006-01-05 23:17:44 +00:00
|
|
|
if (hRes != DD_OK)
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug, "error flipping");
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
} 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 */
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_BltFast (ddrawsink->extern_surface, 0, 0,
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->surface, NULL, DDBLTFAST_WAIT);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/*blit to extern surface (Blt will scale the video the dest rect surface if needed) */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Blt (ddrawsink->extern_surface,
|
|
|
|
&destsurf_rect, surface->surface, NULL, DDBLT_WAIT, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*blit to our primary surface */
|
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->surface, NULL, DDBLT_WAIT, NULL);
|
|
|
|
if (hRes != DD_OK)
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
2007-02-11 15:26:49 +00:00
|
|
|
"IDirectDrawSurface7_Blt returned %s", DDErrorString (hRes));
|
2006-07-24 21:43:06 +00:00
|
|
|
else
|
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
2007-01-03 19:54:33 +00:00
|
|
|
"allocated surface was blit to our primary");
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2007-02-11 15:26:49 +00:00
|
|
|
DDSURFACEDESC2 dd_surface_desc;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
//create an instance of the ddraw object
|
|
|
|
hRes =
|
|
|
|
DirectDrawCreateEx ( /*DDCREATE_EMULATIONONLY */ 0,
|
|
|
|
(void **) &ddrawsink->ddraw_object, &IID_IDirectDraw7, NULL);
|
2006-07-24 21:43:06 +00:00
|
|
|
|
|
|
|
if (hRes != DD_OK || ddrawsink->ddraw_object == NULL) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug, "DirectDrawCreate failed with: %s",
|
|
|
|
DDErrorString (hRes));
|
2006-01-05 23:17:44 +00:00
|
|
|
return FALSE;
|
2006-07-24 21:43:06 +00:00
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* set cooperative level */
|
|
|
|
hRes = IDirectDraw7_SetCooperativeLevel (ddrawsink->ddraw_object,
|
|
|
|
ddrawsink->video_window, DDSCL_NORMAL);
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
if (hRes != DD_OK) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug, "SetCooperativeLevel failed with: %s",
|
|
|
|
DDErrorString (hRes));
|
2006-01-05 23:17:44 +00:00
|
|
|
bRet = FALSE;
|
2006-07-24 21:43:06 +00:00
|
|
|
}
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes =
|
|
|
|
IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
|
2006-01-05 23:17:44 +00:00
|
|
|
&ddrawsink->primary_surface, NULL);
|
2006-07-24 21:43:06 +00:00
|
|
|
if (hRes != DD_OK) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug,
|
|
|
|
"CreateSurface (primary) failed with: %s", DDErrorString (hRes));
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDraw7_Release (ddrawsink->ddraw_object);
|
2006-07-24 21:43:06 +00:00
|
|
|
return FALSE;
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* setup the clipper object */
|
|
|
|
hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
|
2006-01-05 23:17:44 +00:00
|
|
|
&ddrawsink->clipper, NULL);
|
|
|
|
if (hRes == DD_OK) {
|
|
|
|
hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
|
|
|
|
ddrawsink->video_window);
|
2007-02-11 15:26:49 +00:00
|
|
|
|
|
|
|
hRes = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->clipper);
|
|
|
|
}
|
2006-07-24 21:43:06 +00:00
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
} else {
|
2007-02-11 15:26:49 +00:00
|
|
|
DDSURFACEDESC2 desc_surface;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
desc_surface.dwSize = sizeof (DDSURFACEDESC2);
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
/*get extern surface size */
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_GetSurfaceDesc (ddrawsink->extern_surface,
|
2006-01-05 23:17:44 +00:00
|
|
|
&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);
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDrawSurface7_GetPixelFormat (ddrawsink->extern_surface,
|
2006-01-05 23:17:44 +00:00
|
|
|
&ddrawsink->dd_pixel_format);
|
|
|
|
if (hRes != DD_OK) {
|
|
|
|
/*error while retrieving ext surface pixel format */
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"GetPixelFormat (ddrawsink->extern_surface) failed with: %s",
|
|
|
|
DDErrorString (hRes));
|
2006-01-05 23:17:44 +00:00
|
|
|
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) {
|
2007-02-11 15:26:49 +00:00
|
|
|
case WM_ERASEBKGND:
|
|
|
|
return TRUE;
|
2006-01-05 23:17:44 +00:00
|
|
|
/* 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;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* signal application we create a window */
|
|
|
|
gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ddrawsink),
|
|
|
|
ddrawsink->video_window);
|
|
|
|
|
2006-11-01 10:19:18 +00:00
|
|
|
ReleaseSemaphore (ddrawsink->window_created_signal, 1, NULL);
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
/*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)
|
|
|
|
{
|
2006-11-01 10:19:18 +00:00
|
|
|
ddrawsink->window_created_signal = CreateSemaphore (NULL, 0, 1, NULL);
|
|
|
|
if (ddrawsink->window_created_signal == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->window_thread = g_thread_create (
|
|
|
|
(GThreadFunc) gst_directdrawsink_window_thread, ddrawsink, TRUE, NULL);
|
|
|
|
|
|
|
|
if (ddrawsink->window_thread == NULL)
|
2006-11-01 10:19:18 +00:00
|
|
|
goto failed;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2006-11-01 10:19:18 +00:00
|
|
|
/* wait maximum 10 seconds for windows creating */
|
|
|
|
if (WaitForSingleObject (ddrawsink->window_created_signal,
|
|
|
|
10000) != WAIT_OBJECT_0)
|
|
|
|
goto failed;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
2006-11-01 10:19:18 +00:00
|
|
|
CloseHandle (ddrawsink->window_created_signal);
|
2006-01-05 23:17:44 +00:00
|
|
|
return TRUE;
|
2006-11-01 10:19:18 +00:00
|
|
|
|
|
|
|
failed:
|
|
|
|
CloseHandle (ddrawsink->window_created_signal);
|
|
|
|
return FALSE;
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gst_directdrawsink_create_ddraw_surfaces (GstDirectDrawSink * ddrawsink)
|
|
|
|
{
|
2007-02-11 15:26:49 +00:00
|
|
|
DDSURFACEDESC2 dd_surface_desc;
|
2006-01-05 23:17:44 +00:00
|
|
|
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;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes =
|
|
|
|
IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
|
2006-01-05 23:17:44 +00:00
|
|
|
&ddrawsink->overlays, NULL);
|
|
|
|
|
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"create_ddraw_surfaces:CreateSurface(overlays) failed %s",
|
2006-01-05 23:17:44 +00:00
|
|
|
DDErrorString (hRes));
|
|
|
|
return FALSE;
|
2006-07-24 21:43:06 +00:00
|
|
|
} else {
|
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"An overlay surfaces flipping chain was created");
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
2006-07-24 21:43:06 +00:00
|
|
|
dd_surface_desc.ddsCaps.dwCaps =
|
|
|
|
DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes =
|
|
|
|
IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
|
2006-01-05 23:17:44 +00:00
|
|
|
&ddrawsink->offscreen_surface, NULL);
|
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug,
|
|
|
|
"create_ddraw_surfaces:CreateSurface(offscreen) failed %s",
|
2006-01-05 23:17:44 +00:00
|
|
|
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
|
2007-02-11 15:26:49 +00:00
|
|
|
EnumModesCallback2 (LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext)
|
2006-01-05 23:17:44 +00:00
|
|
|
{
|
|
|
|
GstDirectDrawSink *ddrawsink = (GstDirectDrawSink *) lpContext;
|
|
|
|
GstCaps *format_caps = NULL;
|
|
|
|
|
|
|
|
if (!ddrawsink || !lpDDSurfaceDesc)
|
|
|
|
return DDENUMRET_CANCEL;
|
|
|
|
|
|
|
|
if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) != DDSD_PIXELFORMAT) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"Display mode found with DDSD_PIXELFORMAT not set");
|
2006-01-05 23:17:44 +00:00
|
|
|
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;
|
2007-02-11 15:26:49 +00:00
|
|
|
DDCAPS ddcaps_hardware;
|
|
|
|
DDCAPS ddcaps_emulation;
|
2006-01-05 23:17:44 +00:00
|
|
|
GstCaps *format_caps = NULL;
|
|
|
|
|
|
|
|
ddrawsink->caps = gst_caps_new_empty ();
|
|
|
|
if (!ddrawsink->caps)
|
|
|
|
return FALSE;
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* get hardware caps */
|
|
|
|
ddcaps_hardware.dwSize = sizeof (DDCAPS);
|
|
|
|
ddcaps_emulation.dwSize = sizeof (DDCAPS);
|
|
|
|
IDirectDraw7_GetCaps (ddrawsink->ddraw_object, &ddcaps_hardware,
|
|
|
|
&ddcaps_emulation);
|
|
|
|
|
|
|
|
/* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw emulation layer can do it */
|
|
|
|
|
|
|
|
|
|
|
|
if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
|
|
|
|
DDSURFACEDESC2 surface_desc;
|
|
|
|
gint endianness = G_LITTLE_ENDIAN;
|
|
|
|
gint depth;
|
|
|
|
|
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"hardware doesn't support blit from one colorspace to another one. "
|
|
|
|
"so we will create a caps with only the current display mode");
|
|
|
|
|
|
|
|
surface_desc.dwSize = sizeof (DDSURFACEDESC);
|
|
|
|
hRes = IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object, &surface_desc);
|
|
|
|
if (hRes != DD_OK) {
|
|
|
|
GST_CAT_ERROR (directdrawsink_debug,
|
|
|
|
"Error getting the current display mode (%s)", DDErrorString (hRes));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
depth = gst_directdrawsink_get_depth (&surface_desc.ddpfPixelFormat);
|
|
|
|
|
|
|
|
if (surface_desc.ddpfPixelFormat.dwRGBBitCount == 24 ||
|
|
|
|
surface_desc.ddpfPixelFormat.dwRGBBitCount == 32) {
|
|
|
|
/* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
|
|
|
|
endianness = G_BIG_ENDIAN;
|
|
|
|
surface_desc.ddpfPixelFormat.dwRBitMask =
|
|
|
|
GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwRBitMask);
|
|
|
|
surface_desc.ddpfPixelFormat.dwGBitMask =
|
|
|
|
GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwGBitMask);
|
|
|
|
surface_desc.ddpfPixelFormat.dwBBitMask =
|
|
|
|
GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwBBitMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
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, surface_desc.ddpfPixelFormat.dwRGBBitCount,
|
|
|
|
"depth", G_TYPE_INT, depth,
|
|
|
|
"endianness", G_TYPE_INT, endianness,
|
|
|
|
"red_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwRBitMask,
|
|
|
|
"green_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwGBitMask,
|
|
|
|
"blue_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwBBitMask, NULL);
|
|
|
|
|
|
|
|
if (format_caps) {
|
|
|
|
gst_caps_append (ddrawsink->caps, format_caps);
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_INFO (directdrawsink_debug, "returning caps %s",
|
|
|
|
gst_caps_to_string (ddrawsink->caps));
|
|
|
|
|
|
|
|
return ddrawsink->caps;
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
|
|
|
"the hardware can blit from one colorspace to another, "
|
|
|
|
"then enumerate the colorspace supported by the hardware");
|
|
|
|
|
|
|
|
/* enumerate display modes exposed by directdraw object
|
|
|
|
to know supported RGB mode */
|
2006-01-05 23:17:44 +00:00
|
|
|
hRes =
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDraw7_EnumDisplayModes (ddrawsink->ddraw_object,
|
|
|
|
DDEDM_REFRESHRATES, NULL, ddrawsink, EnumModesCallback2);
|
2006-01-05 23:17:44 +00:00
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_WARNING (directdrawsink_debug, "EnumDisplayModes returns: %s",
|
|
|
|
DDErrorString (hRes));
|
2006-01-05 23:17:44 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enumerate non-rgb modes exposed by directdraw object */
|
2007-02-11 15:26:49 +00:00
|
|
|
/* IDirectDraw7_GetFourCCCodes(ddrawsink->ddraw_object, &dwNbFourccCodes, NULL);
|
|
|
|
if(dwNbFourccCodes != 0)
|
|
|
|
{
|
|
|
|
pdwFourccCodes = g_new0(DWORD, dwNbFourccCodes);
|
|
|
|
if(!pdwFourccCodes)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (FAILED(IDirectDraw7_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);
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
2007-02-11 15:26:49 +00:00
|
|
|
*/
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2007-02-11 15:26:49 +00:00
|
|
|
// GST_CAT_INFO (directdrawsink_debug, "returning caps %s", gst_caps_to_string (ddrawsink->caps));
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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;
|
2006-03-03 23:45:23 +00:00
|
|
|
gint pitch;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
HRESULT hRes;
|
2007-02-11 15:26:49 +00:00
|
|
|
DDSURFACEDESC2 surf_desc, surf_lock_desc;
|
2006-01-05 23:17:44 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-03-03 23:45:23 +00:00
|
|
|
pitch = GST_ROUND_UP_8 (size / surface->height);
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
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 */
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
surf_desc.ddsCaps.dwCaps =
|
|
|
|
DDSCAPS_OFFSCREENPLAIN /* | DDSCAPS_SYSTEMMEMORY */ ;
|
2006-01-05 23:17:44 +00:00
|
|
|
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));
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
hRes = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &surf_desc,
|
2006-01-05 23:17:44 +00:00
|
|
|
&surface->surface, NULL);
|
|
|
|
if (hRes != DD_OK) {
|
2006-07-24 21:43:06 +00:00
|
|
|
/*gst_object_unref (surface);
|
|
|
|
surface = NULL;
|
|
|
|
goto beach; */
|
|
|
|
goto surface_pitch_bad;
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 */
|
2007-02-11 15:26:49 +00:00
|
|
|
lock:
|
|
|
|
hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
|
2006-01-05 23:17:44 +00:00
|
|
|
DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
|
2007-02-11 15:26:49 +00:00
|
|
|
if (hRes == DDERR_SURFACELOST) {
|
|
|
|
IDirectDrawSurface7_Restore (surface->surface);
|
|
|
|
goto lock;
|
|
|
|
}
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->locked = TRUE;
|
|
|
|
|
|
|
|
if (surf_lock_desc.lPitch != pitch) {
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
2007-01-03 19:54:33 +00:00
|
|
|
"DDraw stride/pitch %ld isn't as expected value %d, let's continue allocating buffer.",
|
2006-01-05 23:17:44 +00:00
|
|
|
surf_lock_desc.lPitch, pitch);
|
2006-03-03 23:45:23 +00:00
|
|
|
|
|
|
|
/*Unlock the surface as we will change it to use system memory with a GStreamer compatible pitch */
|
|
|
|
hRes = IDirectDrawSurface_Unlock (surface->surface, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
goto surface_pitch_bad;
|
|
|
|
}
|
|
|
|
|
2006-07-24 21:43:06 +00:00
|
|
|
GST_CAT_INFO (directdrawsink_debug,
|
2007-01-03 19:54:33 +00:00
|
|
|
"allocating a surface of %d bytes (stride=%ld)\n", size,
|
2006-01-05 23:17:44 +00:00
|
|
|
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;
|
2006-03-03 23:45:23 +00:00
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
/* surf_desc.dwSize = sizeof(DDSURFACEDESC2);
|
2006-03-03 23:45:23 +00:00
|
|
|
surf_desc.dwFlags = DDSD_PITCH | DDSD_LPSURFACE | DDSD_HEIGHT | DDSD_WIDTH ||DDSD_PIXELFORMAT;
|
|
|
|
surf_desc.lpSurface = GST_BUFFER (surface)->malloc_data;
|
|
|
|
surf_desc.lPitch = pitch;
|
|
|
|
//surf_desc.dwHeight = surface->height;
|
|
|
|
surf_desc.dwWidth = surface->width;
|
|
|
|
hRes = IDirectDrawSurface7_SetSurfaceDesc(surface->surface, &surf_desc, 0);
|
|
|
|
printf("%\n", DDErrorString(hRes));
|
|
|
|
|
|
|
|
hRes = IDirectDrawSurface7_Lock (surface->surface, NULL, &surf_lock_desc,
|
|
|
|
DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
|
|
|
|
*/
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->surface = NULL;
|
2006-07-24 21:43:06 +00:00
|
|
|
/*printf ("allocating a buffer of %d bytes\n", size); */
|
2006-01-05 23:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep a ref to our sink */
|
|
|
|
surface->ddrawsink = gst_object_ref (ddrawsink);
|
|
|
|
|
2007-01-03 19:54:33 +00:00
|
|
|
/*
|
|
|
|
beach:
|
|
|
|
*/
|
2006-01-05 23:17:44 +00:00
|
|
|
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) {
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Unlock (surface->surface, NULL);
|
2006-01-05 23:17:44 +00:00
|
|
|
surface->locked = FALSE;
|
|
|
|
}
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Release (surface->surface);
|
2006-01-05 23:17:44 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-02-11 15:26:49 +00:00
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
/* Post quit message and wait for our event window thread */
|
2007-02-11 15:26:49 +00:00
|
|
|
if (ddrawsink->video_window && ddrawsink->our_video_window)
|
2006-01-05 23:17:44 +00:00
|
|
|
PostMessage (ddrawsink->video_window, WM_QUIT, 0, 0);
|
2007-02-11 15:26:49 +00:00
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
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->overlays) {
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Release (ddrawsink->overlays);
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->overlays = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->offscreen_surface) {
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->offscreen_surface = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->clipper) {
|
|
|
|
IDirectDrawClipper_Release (ddrawsink->clipper);
|
|
|
|
ddrawsink->clipper = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->primary_surface) {
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDrawSurface7_Release (ddrawsink->primary_surface);
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->primary_surface = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddrawsink->ddraw_object) {
|
2007-02-11 15:26:49 +00:00
|
|
|
IDirectDraw7_Release (ddrawsink->ddraw_object);
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->ddraw_object = NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-11 15:26:49 +00:00
|
|
|
if (ddrawsink->last_buffer) {
|
|
|
|
gst_buffer_unref (ddrawsink->last_buffer);
|
|
|
|
ddrawsink->last_buffer = NULL;
|
|
|
|
}
|
|
|
|
|
2006-01-05 23:17:44 +00:00
|
|
|
ddrawsink->setup = FALSE;
|
|
|
|
}
|